mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-09-28 13:21:30 +02:00
Add ping field, start improving README for 2.0
This commit is contained in:
parent
e937c725bb
commit
6496660633
32
README.md
32
README.md
@ -443,9 +443,39 @@ gamedig --type minecraft --host mc.example.com --port 11234
|
|||||||
|
|
||||||
The output of the command will be in JSON format.
|
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
|
### 1.0
|
||||||
* First official release
|
* First official release
|
||||||
* Node.js 6.0 is now required
|
* Node.js 6.0 is now required
|
||||||
|
@ -21,6 +21,8 @@ class Core extends EventEmitter {
|
|||||||
// Sent to us by QueryRunner
|
// Sent to us by QueryRunner
|
||||||
this.options = null;
|
this.options = null;
|
||||||
this.udpSocket = null;
|
this.udpSocket = null;
|
||||||
|
this.shortestRTT = 0;
|
||||||
|
this.usedTcp = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async runAllAttempts() {
|
async runAllAttempts() {
|
||||||
@ -68,7 +70,6 @@ class Core extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async runOnce() {
|
async runOnce() {
|
||||||
const startMillis = Date.now();
|
|
||||||
const options = this.options;
|
const options = this.options;
|
||||||
if (('host' in options) && !('address' in options)) {
|
if (('host' in options) && !('address' in options)) {
|
||||||
options.address = await this.parseDns(options.host);
|
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
|
// because lots of servers prefix with spaces to try to appear first
|
||||||
state.name = (state.name || '').trim();
|
state.name = (state.name || '').trim();
|
||||||
|
|
||||||
state.duration = Date.now() - startMillis;
|
|
||||||
if (!('connect' in state)) {
|
if (!('connect' in state)) {
|
||||||
state.connect = ''
|
state.connect = ''
|
||||||
+ (state.gameHost || this.options.host || this.options.address)
|
+ (state.gameHost || this.options.host || this.options.address)
|
||||||
+ ':'
|
+ ':'
|
||||||
+ (state.gamePort || this.options.port)
|
+ (state.gamePort || this.options.port)
|
||||||
}
|
}
|
||||||
|
state.ping = this.shortestRTT;
|
||||||
delete state.gameHost;
|
delete state.gameHost;
|
||||||
delete state.gamePort;
|
delete state.gamePort;
|
||||||
|
|
||||||
@ -148,6 +149,23 @@ class Core extends EventEmitter {
|
|||||||
else return await resolveStandard(host);
|
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
|
// utils
|
||||||
/** @returns {Reader} */
|
/** @returns {Reader} */
|
||||||
reader(buffer) {
|
reader(buffer) {
|
||||||
@ -186,6 +204,7 @@ class Core extends EventEmitter {
|
|||||||
* @returns {Promise<T>}
|
* @returns {Promise<T>}
|
||||||
*/
|
*/
|
||||||
async withTcp(fn, port) {
|
async withTcp(fn, port) {
|
||||||
|
this.usedTcp = true;
|
||||||
const address = this.options.address;
|
const address = this.options.address;
|
||||||
if (!port) port = this.options.port;
|
if (!port) port = this.options.port;
|
||||||
this.assertValidPort(port);
|
this.assertValidPort(port);
|
||||||
@ -216,6 +235,7 @@ class Core extends EventEmitter {
|
|||||||
socket.on('ready', resolve);
|
socket.on('ready', resolve);
|
||||||
socket.on('close', () => reject(new Error('TCP Connection Refused')));
|
socket.on('close', () => reject(new Error('TCP Connection Refused')));
|
||||||
});
|
});
|
||||||
|
this.registerRtt(connectionPromise);
|
||||||
connectionTimeout = Promises.createTimeout(this.options.socketTimeout, 'TCP Opening');
|
connectionTimeout = Promises.createTimeout(this.options.socketTimeout, 'TCP Opening');
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
connectionPromise,
|
connectionPromise,
|
||||||
@ -284,10 +304,17 @@ class Core extends EventEmitter {
|
|||||||
let timeout;
|
let timeout;
|
||||||
try {
|
try {
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
const start = Date.now();
|
||||||
|
let end = null;
|
||||||
socketCallback = (fromAddress, fromPort, buffer) => {
|
socketCallback = (fromAddress, fromPort, buffer) => {
|
||||||
try {
|
try {
|
||||||
if (fromAddress !== address) return;
|
if (fromAddress !== address) return;
|
||||||
if (fromPort !== port) return;
|
if (fromPort !== port) return;
|
||||||
|
if (end === null) {
|
||||||
|
end = Date.now();
|
||||||
|
const rtt = end-start;
|
||||||
|
this.registerRtt(rtt);
|
||||||
|
}
|
||||||
this.debugLog(log => {
|
this.debugLog(log => {
|
||||||
log(fromAddress + ':' + fromPort + " <--UDP");
|
log(fromAddress + ':' + fromPort + " <--UDP");
|
||||||
log(HexUtil.debugDump(buffer));
|
log(HexUtil.debugDump(buffer));
|
||||||
@ -307,7 +334,6 @@ class Core extends EventEmitter {
|
|||||||
const wrappedTimeout = new Promise((resolve, reject) => {
|
const wrappedTimeout = new Promise((resolve, reject) => {
|
||||||
timeout.catch((e) => {
|
timeout.catch((e) => {
|
||||||
this.debugLog("UDP timeout detected");
|
this.debugLog("UDP timeout detected");
|
||||||
let success = false;
|
|
||||||
if (onTimeout) {
|
if (onTimeout) {
|
||||||
try {
|
try {
|
||||||
const result = onTimeout();
|
const result = onTimeout();
|
||||||
@ -331,6 +357,12 @@ class Core extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async request(params) {
|
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;
|
let requestPromise;
|
||||||
try {
|
try {
|
||||||
requestPromise = requestAsync({
|
requestPromise = requestAsync({
|
||||||
@ -344,7 +376,10 @@ class Core extends EventEmitter {
|
|||||||
.then((response) => log(params.uri + " <--HTTP " + response.statusCode))
|
.then((response) => log(params.uri + " <--HTTP " + response.statusCode))
|
||||||
.catch(() => {});
|
.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]);
|
return await Promise.race([wrappedPromise, this.abortedPromise]);
|
||||||
} finally {
|
} finally {
|
||||||
requestPromise && requestPromise.cancel();
|
requestPromise && requestPromise.cancel();
|
||||||
|
@ -4,7 +4,10 @@ const gbxremote = require('gbxremote'),
|
|||||||
class Nadeo extends Core {
|
class Nadeo extends Core {
|
||||||
async run(state) {
|
async run(state) {
|
||||||
await this.withClient(async client => {
|
await this.withClient(async client => {
|
||||||
|
const start = Date.now();
|
||||||
await this.methodCall(client, 'Authenticate', this.options.login, this.options.password);
|
await this.methodCall(client, 'Authenticate', this.options.login, this.options.password);
|
||||||
|
this.registerRtt(Date.now()-start);
|
||||||
|
|
||||||
//const data = this.methodCall(client, 'GetStatus');
|
//const data = this.methodCall(client, 'GetStatus');
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user