From eb925681497b289f4909f06a06012f1c072bbd96 Mon Sep 17 00:00:00 2001
From: Frank Elsinga
Date: Sat, 3 Jan 2026 01:16:16 +0100
Subject: [PATCH 09/11] Create autofix.yml
---
.github/workflows/autofix.yml | 41 +++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 .github/workflows/autofix.yml
diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml
new file mode 100644
index 000000000..bf3dee8e6
--- /dev/null
+++ b/.github/workflows/autofix.yml
@@ -0,0 +1,41 @@
+name: autofix.ci
+
+on:
+ push:
+ branches: [ "master", "1.23.X"]
+ pull_request:
+permissions: {}
+
+jobs:
+ autofix:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
+ with: { persist-credentials: false }
+
+ - name: Cache/Restore node_modules
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
+ id: node-modules-cache
+ with:
+ path: node_modules
+ key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
+
+ - name: Setup Node.js
+ uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
+ with:
+ node-version: 24
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Auto-fix JavaScript/Vue linting issues
+ run: npm run lint-fix:js
+ continue-on-error: true
+
+ - name: Auto-fix CSS/SCSS linting issues
+ run: npm run lint-fix:style
+ continue-on-error: true
+
+ - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
\ No newline at end of file
From a1a1797b8e9d70b54f27bdf9430d2f57635b0f18 Mon Sep 17 00:00:00 2001
From: Frank Elsinga
Date: Sat, 3 Jan 2026 01:32:03 +0100
Subject: [PATCH 10/11] Update .github/workflows/autofix.yml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.github/workflows/autofix.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml
index bf3dee8e6..e8217e3a4 100644
--- a/.github/workflows/autofix.yml
+++ b/.github/workflows/autofix.yml
@@ -25,7 +25,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
- node-version: 24
+ node-version: 20
- name: Install dependencies
run: npm ci
From d096e2902cee6448b75a763f3fcffda7267b9dd9 Mon Sep 17 00:00:00 2001
From: Markus Reisenhofer
Date: Sat, 3 Jan 2026 06:56:38 +0100
Subject: [PATCH 11/11] feat(gamedig): Update gamedig implementation to v5
(#4949)
Co-authored-by: Frank Elsinga
---
.../2026-01-02-0713-gamedig-v4-to-v5.js | 198 +++++++++
package-lock.json | 403 +++++-------------
package.json | 2 +-
server/monitor-types/gamedig.js | 8 +-
.../socket-handlers/general-socket-handler.js | 37 +-
test/backend-test/monitors/test-gamedig.js | 20 +-
6 files changed, 349 insertions(+), 319 deletions(-)
create mode 100644 db/knex_migrations/2026-01-02-0713-gamedig-v4-to-v5.js
diff --git a/db/knex_migrations/2026-01-02-0713-gamedig-v4-to-v5.js b/db/knex_migrations/2026-01-02-0713-gamedig-v4-to-v5.js
new file mode 100644
index 000000000..63931a705
--- /dev/null
+++ b/db/knex_migrations/2026-01-02-0713-gamedig-v4-to-v5.js
@@ -0,0 +1,198 @@
+// Migration to update monitor.game from GameDig v4 to v5 game IDs
+// Reference: https://github.com/gamedig/node-gamedig/blob/master/MIGRATE_IDS.md
+
+// Lookup table mapping v4 game IDs to v5 game IDs
+const gameDig4to5IdMap = {
+ "americasarmypg": "aapg",
+ "7d2d": "sdtd",
+ "as": "actionsource",
+ "ageofchivalry": "aoc",
+ "arkse": "ase",
+ "arcasimracing": "asr08",
+ "arma": "aaa",
+ "arma2oa": "a2oa",
+ "armacwa": "acwa",
+ "armar": "armaresistance",
+ "armare": "armareforger",
+ "armagetron": "armagetronadvanced",
+ "bat1944": "battalion1944",
+ "bf1942": "battlefield1942",
+ "bfv": "battlefieldvietnam",
+ "bf2": "battlefield2",
+ "bf2142": "battlefield2142",
+ "bfbc2": "bbc2",
+ "bf3": "battlefield3",
+ "bf4": "battlefield4",
+ "bfh": "battlefieldhardline",
+ "bd": "basedefense",
+ "bs": "bladesymphony",
+ "buildandshoot": "bas",
+ "cod4": "cod4mw",
+ "callofjuarez": "coj",
+ "chivalry": "cmw",
+ "commandos3": "c3db",
+ "cacrenegade": "cacr",
+ "contactjack": "contractjack",
+ "cs15": "counterstrike15",
+ "cs16": "counterstrike16",
+ "cs2": "counterstrike2",
+ "crossracing": "crce",
+ "darkesthour": "dhe4445",
+ "daysofwar": "dow",
+ "deadlydozenpt": "ddpt",
+ "dh2005": "deerhunter2005",
+ "dinodday": "ddd",
+ "dirttrackracing2": "dtr2",
+ "dmc": "deathmatchclassic",
+ "dnl": "dal",
+ "drakan": "dootf",
+ "dys": "dystopia",
+ "em": "empiresmod",
+ "empyrion": "egs",
+ "f12002": "formulaone2002",
+ "flashpointresistance": "ofr",
+ "fivem": "gta5f",
+ "forrest": "theforrest",
+ "graw": "tcgraw",
+ "graw2": "tcgraw2",
+ "giantscitizenkabuto": "gck",
+ "ges": "goldeneyesource",
+ "gore": "gus",
+ "hldm": "hld",
+ "hldms": "hlds",
+ "hlopfor": "hlof",
+ "hl2dm": "hl2d",
+ "hidden": "thehidden",
+ "had2": "hiddendangerous2",
+ "igi2": "i2cs",
+ "il2": "il2sturmovik",
+ "insurgencymic": "imic",
+ "isle": "theisle",
+ "jamesbondnightfire": "jb007n",
+ "jc2mp": "jc2m",
+ "jc3mp": "jc3m",
+ "kingpin": "kloc",
+ "kisspc": "kpctnc",
+ "kspdmp": "kspd",
+ "kzmod": "kreedzclimbing",
+ "left4dead": "l4d",
+ "left4dead2": "l4d2",
+ "m2mp": "m2m",
+ "mohsh": "mohaas",
+ "mohbt": "mohaab",
+ "mohab": "moha",
+ "moh2010": "moh",
+ "mohwf": "mohw",
+ "minecraftbe": "mbe",
+ "mtavc": "gtavcmta",
+ "mtasa": "gtasamta",
+ "ns": "naturalselection",
+ "ns2": "naturalselection2",
+ "nwn": "neverwinternights",
+ "nwn2": "neverwinternights2",
+ "nolf": "tonolf",
+ "nolf2": "nolf2asihw",
+ "pvkii": "pvak2",
+ "ps": "postscriptum",
+ "primalcarnage": "pce",
+ "pc": "projectcars",
+ "pc2": "projectcars2",
+ "prbf2": "prb2",
+ "przomboid": "projectzomboid",
+ "quake1": "quake",
+ "quake3": "q3a",
+ "ragdollkungfu": "rdkf",
+ "r6": "rainbowsix",
+ "r6roguespear": "rs2rs",
+ "r6ravenshield": "rs3rs",
+ "redorchestraost": "roo4145",
+ "redm": "rdr2r",
+ "riseofnations": "ron",
+ "rs2": "rs2v",
+ "samp": "gtasam",
+ "saomp": "gtasao",
+ "savage2": "s2ats",
+ "ss": "serioussam",
+ "ss2": "serioussam2",
+ "ship": "theship",
+ "sinep": "sinepisodes",
+ "sonsoftheforest": "sotf",
+ "swbf": "swb",
+ "swbf2": "swb2",
+ "swjk": "swjkja",
+ "swjk2": "swjk2jo",
+ "takeonhelicopters": "toh",
+ "tf2": "teamfortress2",
+ "terraria": "terrariatshock",
+ "tribes1": "t1s",
+ "ut": "unrealtournament",
+ "ut2003": "unrealtournament2003",
+ "ut2004": "unrealtournament2004",
+ "ut3": "unrealtournament3",
+ "v8supercar": "v8sc",
+ "vcmp": "vcm",
+ "vs": "vampireslayer",
+ "wheeloftime": "wot",
+ "wolfenstein2009": "wolfenstein",
+ "wolfensteinet": "wet",
+ "wurm": "wurmunlimited",
+};
+
+/**
+ * Migrate game IDs from v4 to v5
+ * @param {import("knex").Knex} knex - Knex instance
+ * @returns {Promise}
+ */
+exports.up = async function (knex) {
+ await knex.transaction(async (trx) => {
+ // Get all monitors that use the gamedig type
+ const monitors = await trx("monitor")
+ .select("id", "game")
+ .where("type", "gamedig")
+ .whereNotNull("game");
+
+ // Update each monitor with the new game ID if it needs migration
+ for (const monitor of monitors) {
+ const oldGameId = monitor.game;
+ const newGameId = gameDig4to5IdMap[oldGameId];
+
+ if (newGameId) {
+ await trx("monitor")
+ .where("id", monitor.id)
+ .update({ game: newGameId });
+ }
+ }
+ });
+};
+
+/**
+ * Revert game IDs from v5 back to v4
+ * @param {import("knex").Knex} knex - Knex instance
+ * @returns {Promise}
+ */
+exports.down = async function (knex) {
+ // Create reverse mapping from the same LUT
+ const gameDig5to4IdMap = Object.fromEntries(
+ Object.entries(gameDig4to5IdMap).map(([ v4, v5 ]) => [ v5, v4 ])
+ );
+
+ await knex.transaction(async (trx) => {
+ // Get all monitors that use the gamedig type
+ const monitors = await trx("monitor")
+ .select("id", "game")
+ .where("type", "gamedig")
+ .whereNotNull("game");
+
+ // Revert each monitor back to the old game ID if it was migrated
+ for (const monitor of monitors) {
+ const newGameId = monitor.game;
+ const oldGameId = gameDig5to4IdMap[newGameId];
+
+ if (oldGameId) {
+ await trx("monitor")
+ .where("id", monitor.id)
+ .update({ game: oldGameId });
+ }
+ }
+ });
+};
diff --git a/package-lock.json b/package-lock.json
index ab56e410d..12ace22aa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,7 +34,7 @@
"express-static-gzip": "~2.1.7",
"feed": "^4.2.2",
"form-data": "~4.0.0",
- "gamedig": "^4.2.0",
+ "gamedig": "^5.0.1",
"html-escaper": "^3.0.3",
"http-cookie-agent": "~5.0.4",
"http-graceful-shutdown": "~3.1.7",
@@ -4956,12 +4956,12 @@
"license": "BSD-3-Clause"
},
"node_modules/@sindresorhus/is": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
- "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+ "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==",
"license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14.16"
},
"funding": {
"url": "https://github.com/sindresorhus/is?sponsor=1"
@@ -5760,18 +5760,6 @@
"@popperjs/core": "^2.9.2"
}
},
- "node_modules/@types/cacheable-request": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
- "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
- "license": "MIT",
- "dependencies": {
- "@types/http-cache-semantics": "*",
- "@types/keyv": "^3.1.4",
- "@types/node": "*",
- "@types/responselike": "^1.0.0"
- }
- },
"node_modules/@types/connect": {
"version": "3.4.38",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
@@ -5893,15 +5881,6 @@
"integrity": "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==",
"license": "MIT"
},
- "node_modules/@types/keyv": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
- "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/koa": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.15.0.tgz",
@@ -5984,15 +5963,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/responselike": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
- "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
@@ -7820,54 +7790,30 @@
}
},
"node_modules/cacheable-lookup": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz",
- "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+ "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
"license": "MIT",
"engines": {
- "node": ">=10.6.0"
+ "node": ">=14.16"
}
},
"node_modules/cacheable-request": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
- "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
+ "version": "10.2.14",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
+ "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
"license": "MIT",
"dependencies": {
- "clone-response": "^1.0.2",
- "get-stream": "^5.1.0",
- "http-cache-semantics": "^4.0.0",
- "keyv": "^4.0.0",
- "lowercase-keys": "^2.0.0",
- "normalize-url": "^6.0.1",
- "responselike": "^2.0.0"
+ "@types/http-cache-semantics": "^4.0.2",
+ "get-stream": "^6.0.1",
+ "http-cache-semantics": "^4.1.1",
+ "keyv": "^4.5.3",
+ "mimic-response": "^4.0.0",
+ "normalize-url": "^8.0.0",
+ "responselike": "^3.0.0"
},
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/cacheable-request/node_modules/get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "license": "MIT",
- "dependencies": {
- "pump": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cacheable-request/node_modules/lowercase-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
- "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
+ "node": ">=14.16"
}
},
"node_modules/call-bind": {
@@ -8200,18 +8146,6 @@
"node": ">=12"
}
},
- "node_modules/clone-response": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
- "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
- "license": "MIT",
- "dependencies": {
- "mimic-response": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
@@ -9543,6 +9477,14 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/emitter-component": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.2.tgz",
+ "integrity": "sha512-QdXO3nXOzZB4pAjM0n6ZE+R9/+kPpECA/XSELIcc54NeYVnBqIk+4DFiBgK+8QbV3mdvTG6nedl7dTYgO+5wDw==",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -10365,7 +10307,6 @@
}
],
"license": "MIT",
- "optional": true,
"dependencies": {
"strnum": "^2.1.0"
},
@@ -10686,10 +10627,13 @@
}
},
"node_modules/form-data-encoder": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz",
- "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==",
- "license": "MIT"
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+ "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.17"
+ }
},
"node_modules/formdata-node": {
"version": "6.0.3",
@@ -10894,171 +10838,42 @@
}
},
"node_modules/gamedig": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/gamedig/-/gamedig-4.3.2.tgz",
- "integrity": "sha512-TjYwybvy8HNAhkv2EJccd5HROIiMeMriWmeX8vT8m5Ibat5JMzVpugzsD8L8XZVrOfiXnVg/9DhWYM8k/VG/vw==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/gamedig/-/gamedig-5.3.2.tgz",
+ "integrity": "sha512-R2b1LwjW783PZsHRl9M8R06UkvJwXmJ6PDKk48UukJQ9ktiwrCeAk90MAZx6nF3oA444uf7r5eHjfaYbNoSV+Q==",
"license": "MIT",
"dependencies": {
- "cheerio": "1.0.0-rc.10",
+ "fast-xml-parser": "5.2.5",
"gbxremote": "0.2.1",
- "got": "12.1.0",
- "iconv-lite": "0.6.3",
- "long": "5.2.0",
- "minimist": "1.2.6",
- "punycode": "2.1.1",
+ "got": "13.0.0",
+ "iconv-lite": "0.7.0",
+ "long": "5.3.2",
+ "minimist": "1.2.8",
"seek-bzip": "2.0.0",
+ "telnet-client": "2.2.6",
"varint": "6.0.0"
},
"bin": {
"gamedig": "bin/gamedig.js"
},
"engines": {
- "node": ">=14.0.0"
+ "node": ">=16.20.0"
}
},
- "node_modules/gamedig/node_modules/cheerio": {
- "version": "1.0.0-rc.10",
- "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
- "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
+ "node_modules/gamedig/node_modules/iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"license": "MIT",
"dependencies": {
- "cheerio-select": "^1.5.0",
- "dom-serializer": "^1.3.2",
- "domhandler": "^4.2.0",
- "htmlparser2": "^6.1.0",
- "parse5": "^6.0.1",
- "parse5-htmlparser2-tree-adapter": "^6.0.1",
- "tslib": "^2.2.0"
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
- "node": ">= 6"
+ "node": ">=0.10.0"
},
"funding": {
- "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
- }
- },
- "node_modules/gamedig/node_modules/cheerio-select": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz",
- "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "css-select": "^4.3.0",
- "css-what": "^6.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.3.1",
- "domutils": "^2.8.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/fb55"
- }
- },
- "node_modules/gamedig/node_modules/css-select": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
- "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "boolbase": "^1.0.0",
- "css-what": "^6.0.1",
- "domhandler": "^4.3.1",
- "domutils": "^2.8.0",
- "nth-check": "^2.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/fb55"
- }
- },
- "node_modules/gamedig/node_modules/dom-serializer": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
- "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
- "license": "MIT",
- "dependencies": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.2.0",
- "entities": "^2.0.0"
- },
- "funding": {
- "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
- }
- },
- "node_modules/gamedig/node_modules/domhandler": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
- "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "domelementtype": "^2.2.0"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/gamedig/node_modules/domutils": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
- "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.2.0"
- },
- "funding": {
- "url": "https://github.com/fb55/domutils?sponsor=1"
- }
- },
- "node_modules/gamedig/node_modules/entities": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
- "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
- "license": "BSD-2-Clause",
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/gamedig/node_modules/htmlparser2": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
- "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
- "funding": [
- "https://github.com/fb55/htmlparser2?sponsor=1",
- {
- "type": "github",
- "url": "https://github.com/sponsors/fb55"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0",
- "domutils": "^2.5.2",
- "entities": "^2.0.0"
- }
- },
- "node_modules/gamedig/node_modules/long": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz",
- "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==",
- "license": "Apache-2.0"
- },
- "node_modules/gamedig/node_modules/parse5": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
- "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
- "license": "MIT"
- },
- "node_modules/gamedig/node_modules/parse5-htmlparser2-tree-adapter": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
- "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
- "license": "MIT",
- "dependencies": {
- "parse5": "^6.0.1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/gauge": {
@@ -11415,27 +11230,25 @@
}
},
"node_modules/got": {
- "version": "12.1.0",
- "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz",
- "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==",
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz",
+ "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==",
"license": "MIT",
"dependencies": {
- "@sindresorhus/is": "^4.6.0",
+ "@sindresorhus/is": "^5.2.0",
"@szmarczak/http-timer": "^5.0.1",
- "@types/cacheable-request": "^6.0.2",
- "@types/responselike": "^1.0.0",
- "cacheable-lookup": "^6.0.4",
- "cacheable-request": "^7.0.2",
+ "cacheable-lookup": "^7.0.0",
+ "cacheable-request": "^10.2.8",
"decompress-response": "^6.0.0",
- "form-data-encoder": "1.7.1",
+ "form-data-encoder": "^2.1.2",
"get-stream": "^6.0.1",
"http2-wrapper": "^2.1.10",
"lowercase-keys": "^3.0.0",
"p-cancelable": "^3.0.0",
- "responselike": "^2.0.0"
+ "responselike": "^3.0.0"
},
"engines": {
- "node": ">=14.16"
+ "node": ">=16"
},
"funding": {
"url": "https://github.com/sindresorhus/got?sponsor=1"
@@ -13623,12 +13436,15 @@
}
},
"node_modules/mimic-response": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
- "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+ "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
"license": "MIT",
"engines": {
- "node": ">=4"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimalistic-assert": {
@@ -13653,10 +13469,13 @@
}
},
"node_modules/minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
- "license": "MIT"
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
"node_modules/minimist-options": {
"version": "4.1.0",
@@ -14107,6 +13926,12 @@
"node": ">= 0.6"
}
},
+ "node_modules/net": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz",
+ "integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ==",
+ "license": "MIT"
+ },
"node_modules/net-snmp": {
"version": "3.26.0",
"resolved": "https://registry.npmjs.org/net-snmp/-/net-snmp-3.26.0.tgz",
@@ -14388,12 +14213,12 @@
}
},
"node_modules/normalize-url": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
- "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz",
+ "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==",
"license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -16272,26 +16097,20 @@
}
},
"node_modules/responselike": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
- "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+ "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
"license": "MIT",
"dependencies": {
- "lowercase-keys": "^2.0.0"
+ "lowercase-keys": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/responselike/node_modules/lowercase-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
- "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/retimer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz",
@@ -17254,6 +17073,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/stream": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stream/-/stream-0.0.2.tgz",
+ "integrity": "sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g==",
+ "license": "MIT",
+ "dependencies": {
+ "emitter-component": "^1.1.1"
+ }
+ },
"node_modules/stream-shift": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
@@ -17552,8 +17380,7 @@
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/style-search": {
"version": "0.1.0",
@@ -17969,6 +17796,20 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/telnet-client": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/telnet-client/-/telnet-client-2.2.6.tgz",
+ "integrity": "sha512-ZUYrLsPtQupQww3eSEORDVOb6ztdtKEghya6TVXPo2tg/UQq2pn5rHhvwuUvyYpbnsoqdNY1fyD1GNkXHR8dYA==",
+ "license": "MIT",
+ "dependencies": {
+ "net": "^1.0.2",
+ "stream": "^0.0.2"
+ },
+ "funding": {
+ "type": "paypal",
+ "url": "https://paypal.me/kozjak"
+ }
+ },
"node_modules/temp-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
@@ -19130,16 +18971,6 @@
"proxy-from-env": "^1.1.0"
}
},
- "node_modules/wait-on/node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/web-push": {
"version": "3.6.7",
"resolved": "https://registry.npmjs.org/web-push/-/web-push-3.6.7.tgz",
diff --git a/package.json b/package.json
index 987b5af52..09811f1ad 100644
--- a/package.json
+++ b/package.json
@@ -95,7 +95,7 @@
"express-static-gzip": "~2.1.7",
"feed": "^4.2.2",
"form-data": "~4.0.0",
- "gamedig": "^4.2.0",
+ "gamedig": "^5.0.1",
"html-escaper": "^3.0.3",
"http-cookie-agent": "~5.0.4",
"http-graceful-shutdown": "~3.1.7",
diff --git a/server/monitor-types/gamedig.js b/server/monitor-types/gamedig.js
index b20c2435c..35a015f98 100644
--- a/server/monitor-types/gamedig.js
+++ b/server/monitor-types/gamedig.js
@@ -1,6 +1,6 @@
const { MonitorType } = require("./monitor-type");
-const { UP, DOWN } = require("../../src/util");
-const Gamedig = require("gamedig");
+const { UP } = require("../../src/util");
+const { GameDig } = require("gamedig");
const dns = require("dns").promises;
const net = require("net");
@@ -11,15 +11,13 @@ class GameDigMonitorType extends MonitorType {
* @inheritdoc
*/
async check(monitor, heartbeat, server) {
- heartbeat.status = DOWN;
-
let host = monitor.hostname;
if (net.isIP(host) === 0) {
host = await this.resolveHostname(host);
}
try {
- const state = await Gamedig.query({
+ const state = await GameDig.query({
type: monitor.game,
host: host,
port: monitor.port,
diff --git a/server/socket-handlers/general-socket-handler.js b/server/socket-handlers/general-socket-handler.js
index b996efe7b..ad57d7b1e 100644
--- a/server/socket-handlers/general-socket-handler.js
+++ b/server/socket-handlers/general-socket-handler.js
@@ -2,30 +2,35 @@ const { log } = require("../../src/util");
const { Settings } = require("../settings");
const { sendInfo } = require("../client");
const { checkLogin } = require("../util-server");
-const GameResolver = require("gamedig/lib/GameResolver");
+const { games } = require("gamedig");
const { testChrome } = require("../monitor-types/real-browser-monitor-type");
const fsAsync = require("fs").promises;
const path = require("path");
-let gameResolver = new GameResolver();
-let gameList = null;
-
/**
* Get a game list via GameDig
- * @returns {object[]} list of games supported by GameDig
+ * @returns {object} list of games supported by GameDig
*/
function getGameList() {
- if (gameList == null) {
- gameList = gameResolver._readGames().games.sort((a, b) => {
- if ( a.pretty < b.pretty ) {
- return -1;
- }
- if ( a.pretty > b.pretty ) {
- return 1;
- }
- return 0;
- });
- }
+ let gameList = [];
+ gameList = Object.keys(games).map(key => {
+ const item = games[key];
+ return {
+ keys: [ key ],
+ pretty: item.name,
+ options: item.options,
+ extra: item.extra || {}
+ };
+ });
+ gameList.sort((a, b) => {
+ if ( a.pretty < b.pretty ) {
+ return -1;
+ }
+ if ( a.pretty > b.pretty ) {
+ return 1;
+ }
+ return 0;
+ });
return gameList;
}
diff --git a/test/backend-test/monitors/test-gamedig.js b/test/backend-test/monitors/test-gamedig.js
index 57e7a89dc..5274e69dc 100644
--- a/test/backend-test/monitors/test-gamedig.js
+++ b/test/backend-test/monitors/test-gamedig.js
@@ -1,15 +1,15 @@
const { describe, test, mock } = require("node:test");
const assert = require("node:assert");
const { GameDigMonitorType } = require("../../../server/monitor-types/gamedig");
-const { UP, DOWN, PENDING } = require("../../../src/util");
+const { UP, PENDING } = require("../../../src/util");
const net = require("net");
-const Gamedig = require("gamedig");
+const { GameDig } = require("gamedig");
describe("GameDig Monitor", () => {
test("check() sets status to UP when Gamedig.query returns valid server response", async () => {
const gamedigMonitor = new GameDigMonitorType();
- mock.method(Gamedig, "query", async () => {
+ mock.method(GameDig, "query", async () => {
return {
name: "Test Minecraft Server",
ping: 42,
@@ -43,7 +43,7 @@ describe("GameDig Monitor", () => {
test("check() resolves hostname to IP address when hostname is not an IP", async () => {
const gamedigMonitor = new GameDigMonitorType();
- mock.method(Gamedig, "query", async (options) => {
+ mock.method(GameDig, "query", async (options) => {
assert.ok(
net.isIP(options.host) !== 0,
`Expected IP address, got ${options.host}`
@@ -82,7 +82,7 @@ describe("GameDig Monitor", () => {
let capturedOptions = null;
- mock.method(Gamedig, "query", async (options) => {
+ mock.method(GameDig, "query", async (options) => {
capturedOptions = options;
return {
name: "Test Server",
@@ -117,7 +117,7 @@ describe("GameDig Monitor", () => {
let capturedOptions = null;
- mock.method(Gamedig, "query", async (options) => {
+ mock.method(GameDig, "query", async (options) => {
capturedOptions = options;
return {
name: "Test Server",
@@ -152,7 +152,7 @@ describe("GameDig Monitor", () => {
let capturedOptions = null;
- mock.method(Gamedig, "query", async (options) => {
+ mock.method(GameDig, "query", async (options) => {
capturedOptions = options;
return {
name: "Test Server",
@@ -189,7 +189,7 @@ describe("GameDig Monitor", () => {
let capturedOptions = null;
- mock.method(Gamedig, "query", async (options) => {
+ mock.method(GameDig, "query", async (options) => {
capturedOptions = options;
return {
name: "Test Server",
@@ -219,7 +219,7 @@ describe("GameDig Monitor", () => {
}
});
- test("check() sets status to DOWN and rejects when game server is unreachable", async () => {
+ test("check() rejects when game server is unreachable", async () => {
const gamedigMonitor = new GameDigMonitorType();
const monitor = {
@@ -238,8 +238,6 @@ describe("GameDig Monitor", () => {
gamedigMonitor.check(monitor, heartbeat, {}),
/Error/
);
-
- assert.strictEqual(heartbeat.status, DOWN);
});
test("resolveHostname() returns IP address when given valid hostname", async () => {