Add ping field, start improving README for 2.0

This commit is contained in:
mmorrison 2019-01-12 21:32:24 -06:00
parent e937c725bb
commit 6496660633
3 changed files with 73 additions and 5 deletions

View file

@ -443,9 +443,39 @@ gamedig --type minecraft --host mc.example.com --port 11234
The output of the command will be in JSON format.
Major Version Changes
Changelog
---
### 2.0
##### Breaking changes
* Node 8 is now required
* Removed the `port_query` option. You can now pass either the server's game port **or** query port in the `port` option, and
GameDig will automatically discover the proper port to query. Passing the query port is more likely be successful in
unusual cases, as otherwise it must be automatically derived from the game port.
* Removed `callback` parameter from Gamedig.query. Only promises are now supported. If you would like to continue
using callbacks, you can use node's `util.callbackify` function to convert the method to callback format.
* Removed `query` field from response object, as it was poorly documented and unstable.
##### Minor Changes
* Rewrote core to use promises extensively for better error-handling. Async chains have been dramatically simplified
by using async/await across the codebase, eliminating callback chains and the 'async' dependency.
* Replaced `--output pretty` cli parameter with `--pretty`.
* You can now query from CLI using shorthand syntax: `gamedig --type <gameid> <ip>[:<port>]`
* UDP socket is only opened if needed by a query.
* Automatic query port detection -- If provided with a non-standard port, gamedig will attempt to discover if it is a
game port or query port by querying twice: once to the port provided, and once to the port including the game's query
port offset (if available).
* Simplified detection of BC2 when using battlefield protocol.
* Fixed buildandshoot not reading player list
* Added new `connect` field to the response object. This will typically include the game's `ip:port` (the port will reflect the server's
game port, even if you passed in a query port in your request). For some games, this may be a server ID or connection url
if an IP:Port is not appropriate.
* Added new `ping` field (in milliseconds) to the response object. Since icmp packets are often blocked by NATs, and node has poor support
for raw sockets, this time is derived from the rtt of one of the UDP requests, tcp socket connection, or http requests made
during the query.
### 1.0
* First official release
* Node.js 6.0 is now required

View file

@ -21,6 +21,8 @@ class Core extends EventEmitter {
// Sent to us by QueryRunner
this.options = null;
this.udpSocket = null;
this.shortestRTT = 0;
this.usedTcp = false;
}
async runAllAttempts() {
@ -68,7 +70,6 @@ class Core extends EventEmitter {
}
async runOnce() {
const startMillis = Date.now();
const options = this.options;
if (('host' in options) && !('address' in options)) {
options.address = await this.parseDns(options.host);
@ -94,13 +95,13 @@ class Core extends EventEmitter {
// because lots of servers prefix with spaces to try to appear first
state.name = (state.name || '').trim();
state.duration = Date.now() - startMillis;
if (!('connect' in state)) {
state.connect = ''
+ (state.gameHost || this.options.host || this.options.address)
+ ':'
+ (state.gamePort || this.options.port)
}
state.ping = this.shortestRTT;
delete state.gameHost;
delete state.gamePort;
@ -148,6 +149,23 @@ class Core extends EventEmitter {
else return await resolveStandard(host);
}
/** Param can be a time in ms, or a promise (which will be timed) */
registerRtt(param) {
if (param.then) {
const start = Date.now();
param.then(() => {
const end = Date.now();
const rtt = end - start;
this.registerRtt(rtt);
}).catch(() => {});
} else {
this.debugLog("Registered RTT: " + param + "ms");
if (this.shortestRTT === 0 || param < this.shortestRTT) {
this.shortestRTT = param;
}
}
}
// utils
/** @returns {Reader} */
reader(buffer) {
@ -186,6 +204,7 @@ class Core extends EventEmitter {
* @returns {Promise<T>}
*/
async withTcp(fn, port) {
this.usedTcp = true;
const address = this.options.address;
if (!port) port = this.options.port;
this.assertValidPort(port);
@ -216,6 +235,7 @@ class Core extends EventEmitter {
socket.on('ready', resolve);
socket.on('close', () => reject(new Error('TCP Connection Refused')));
});
this.registerRtt(connectionPromise);
connectionTimeout = Promises.createTimeout(this.options.socketTimeout, 'TCP Opening');
await Promise.race([
connectionPromise,
@ -284,10 +304,17 @@ class Core extends EventEmitter {
let timeout;
try {
const promise = new Promise((resolve, reject) => {
const start = Date.now();
let end = null;
socketCallback = (fromAddress, fromPort, buffer) => {
try {
if (fromAddress !== address) return;
if (fromPort !== port) return;
if (end === null) {
end = Date.now();
const rtt = end-start;
this.registerRtt(rtt);
}
this.debugLog(log => {
log(fromAddress + ':' + fromPort + " <--UDP");
log(HexUtil.debugDump(buffer));
@ -307,7 +334,6 @@ class Core extends EventEmitter {
const wrappedTimeout = new Promise((resolve, reject) => {
timeout.catch((e) => {
this.debugLog("UDP timeout detected");
let success = false;
if (onTimeout) {
try {
const result = onTimeout();
@ -331,6 +357,12 @@ class Core extends EventEmitter {
}
async request(params) {
// If we haven't opened a raw tcp socket yet during this query, just open one and then immediately close it.
// This will give us a much more accurate RTT than using the rtt of the http request.
if (!this.usedTcp) {
await this.withTcp(() => {});
}
let requestPromise;
try {
requestPromise = requestAsync({
@ -344,7 +376,10 @@ class Core extends EventEmitter {
.then((response) => log(params.uri + " <--HTTP " + response.statusCode))
.catch(() => {});
});
const wrappedPromise = requestPromise.then(response => response.body);
const wrappedPromise = requestPromise.then(response => {
if (response.statusCode !== 200) throw new Error("Bad status code: " + response.statusCode);
return response.body;
});
return await Promise.race([wrappedPromise, this.abortedPromise]);
} finally {
requestPromise && requestPromise.cancel();

View file

@ -4,7 +4,10 @@ const gbxremote = require('gbxremote'),
class Nadeo extends Core {
async run(state) {
await this.withClient(async client => {
const start = Date.now();
await this.methodCall(client, 'Authenticate', this.options.login, this.options.password);
this.registerRtt(Date.now()-start);
//const data = this.methodCall(client, 'GetStatus');
{