diff --git a/CHANGELOG.md b/CHANGELOG.md index 5870559..6e4cd4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,10 +31,12 @@ * Added code examples. * New stable field: `queryPort` - this number indicates what was the port that the query was done on, 0 indicates none if not applicable. * Fixed `numplayers` not having a default value. -* New option: `stripColors` (defaults to `true`) for protocols that strips colors: unreal2, savage2, quake3, nadeo, gamespy2, doom3, armagetron. -* New option: `requestRulesRequired` (defaults to `false`) Valve games only. `requestRules` is always required to have a response or the query will timeout. -* New option: `requestPlayersRequired` (defaults to `false`) Valve games only. Querying players is always required to have a response or the query will timeout. Some [games](GAMES_LIST.md) may not provide a players response. -* New option: `address` (defaults to `undefined`) Override the IP address of the server skipping DNS resolution. When set, host will not be resolved, instead address will be connected to. However, some protocols still use host for other reasons e.g. as part of the query. +* New options: + * `portCache` (defaults to `true`) after you queried a server, the second time you query that exact server (identified by specified ip and port), first add an attempt to query with the last successful port. + * `stripColors` (defaults to `true`) for protocols that strips colors: unreal2, savage2, quake3, nadeo, gamespy2, doom3, armagetron. + * `requestRulesRequired` (defaults to `false`) Valve games only. `requestRules` is always required to have a response or the query will timeout. + * `requestPlayersRequired` (defaults to `false`) Valve games only. Querying players is always required to have a response or the query will timeout. Some [games](GAMES_LIST.md) may not provide a players response. + * `address` (defaults to `undefined`) Override the IP address of the server skipping DNS resolution. When set, host will not be resolved, instead address will be connected to. However, some protocols still use host for other reasons e.g. as part of the query. #### Games * Removed the players::setNum method, the library will no longer add empty players as diff --git a/README.md b/README.md index e8dcd11..f80b054 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Confused on how this works, or you want to see more? Checkout the [examples](/ex | **requestRulesRequired** | boolean | false | Valve games only. `requestRules` is always required to have a response or the query will timeout. | | **requestPlayersRequired** | boolean | false | Valve games only. Querying players is always required to have a response or the query will timeout. Some [games](GAMES_LIST.md) may not provide a players response. | | **stripColors** | boolean | true | Enables stripping colors for protocols: unreal2, savage2, quake3, nadeo, gamespy2, doom3, armagetron. | +| **portCache** | boolean | true | After you queried a server, the second time you query that exact server (identified by specified ip and port), first add an attempt to query with the last successful port. | ## Query Response diff --git a/bin/gamedig.js b/bin/gamedig.js index d033596..c9420d3 100644 --- a/bin/gamedig.js +++ b/bin/gamedig.js @@ -6,10 +6,11 @@ import Minimist from 'minimist' import { GameDig } from './../lib/index.js' const argv = Minimist(process.argv.slice(2), { - boolean: ['pretty', 'debug', 'givenPortOnly', 'requestRules', 'requestRulesRequired', 'requestPlayersRequired', 'stripColors'], + boolean: ['pretty', 'debug', 'givenPortOnly', 'requestRules', 'requestRulesRequired', 'requestPlayersRequired', 'stripColors', 'portCache'], string: ['guildId', 'listenUdpPort', 'ipFamily'], default: { - stripColors: true + stripColors: true, + portCache: true } }) diff --git a/lib/QueryRunner.js b/lib/QueryRunner.js index c74af84..7f0eb45 100644 --- a/lib/QueryRunner.js +++ b/lib/QueryRunner.js @@ -7,6 +7,7 @@ const defaultOptions = { attemptTimeout: 10000, maxAttempts: 1, stripColors: true, + portCache: true, ipFamily: 0 } @@ -15,6 +16,7 @@ export default class QueryRunner { this.udpSocket = new GlobalUdpSocket({ port: runnerOpts.listenUdpPort }) + this.portCache = {} } async run (userOptions) { @@ -50,11 +52,18 @@ export default class QueryRunner { gameQueryPortOffset ? portOffsetArray = [gameQueryPortOffset] : portOffsetArray = [0] } + const cachedPort = this.portCache[`${userOptions.address}:${userOptions.port}`] + + if (cachedPort && optionsCollection.portCache) { + addAttemptWithPort(cachedPort) + } + if (userOptions.port) { if (!userOptions.givenPortOnly) { portOffsetArray.forEach((portOffset) => { addAttemptWithPort(userOptions.port + portOffset) }) if (userOptions.port === gameOptions.port && gameQueryPort) { addAttemptWithPort(gameQueryPort) } } + attempts.push(optionsCollection) } else if (gameQueryPort) { addAttemptWithPort(gameQueryPort) @@ -74,7 +83,11 @@ export default class QueryRunner { attemptNum++ try { - return await this._attempt(attempt) + const response = await this._attempt(attempt) + if (attempt.portCache) { + this.portCache[`${userOptions.address}:${userOptions.port}`] = attempt.port + } + return response } catch (e) { e.stack = 'Attempt #' + attemptNum + ' - Port=' + attempt.port + ' Retry=' + (retry) + ':\n' + e.stack errors.push(e)