From b1f112415d1c2f1cfd01d95bea75615fd746514a Mon Sep 17 00:00:00 2001 From: Jeff Hobson Date: Wed, 9 Mar 2022 13:05:18 -0500 Subject: [PATCH 1/3] Send messages via serialized JSON This is to coincide with a change to the LiveSplit.Server repo --- src/LiveSplitClient.js | 65 +++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/src/LiveSplitClient.js b/src/LiveSplitClient.js index e4f12b6..d937835 100644 --- a/src/LiveSplitClient.js +++ b/src/LiveSplitClient.js @@ -94,10 +94,10 @@ class LiveSplitClient extends EventEmitter { /** * Send command to the LiveSplit Server instance. * @param {string} command - Existing LiveSplit Server command without linebreaks. - * @param {boolean} [expectResponse=true] - Expect response from the server. + * @param {object} [data] - Additional data to be sent with the command. * @returns {Promise|boolean} - Promise if answer was expected, else true. */ - send(command, expectResponse = true) { + send(command, data) { if (!this._connected) throw new Error('Client must be connected to the server!'); @@ -106,12 +106,10 @@ class LiveSplitClient extends EventEmitter { this._checkDisallowedSymbols(command); - this._socket.write(`${command}\r\n`); + var jsonString = JSON.stringify({ command, data }); + this._socket.write(`${jsonString}\r\n`); - if (expectResponse) - return this._waitForResponse(); - else - return true; + return this._waitForResponse(); } _waitForResponse() { @@ -147,7 +145,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ startTimer() { - return this.send('starttimer', false); + return this.send('starttimer'); } /** @@ -155,7 +153,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ startOrSplit() { - return this.send('startorsplit', false); + return this.send('startorsplit'); } /** @@ -163,7 +161,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ split() { - return this.send('split', false); + return this.send('split'); } /** @@ -171,7 +169,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ unsplit() { - return this.send('unsplit', false); + return this.send('unsplit'); } /** @@ -179,7 +177,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ skipSplit() { - return this.send('skipsplit', false); + return this.send('skipsplit'); } /** @@ -187,7 +185,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ pause() { - return this.send('pause', false); + return this.send('pause'); } /** @@ -195,7 +193,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ resume() { - return this.send('resume', false); + return this.send('resume'); } /** @@ -203,7 +201,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ reset() { - return this.send('reset', false); + return this.send('reset'); } /** @@ -213,7 +211,7 @@ class LiveSplitClient extends EventEmitter { initGameTime() { if (this._initGameTimeOnce) return false; this._initGameTimeOnce = true; - return this.send('initgametime', false); + return this.send('initgametime'); } /** @@ -222,7 +220,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ setGameTime(time) { - return this.send(`setgametime ${time}`, false); + return this.send('setgametime', { time }); } /** @@ -231,7 +229,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ setLoadingTimes(time) { - return this.send(`setloadingtimes ${time}`, false); + return this.send('setloadingtimes', { time }); } /** @@ -239,7 +237,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ pauseGameTime() { - return this.send('pausegametime', false); + return this.send('pausegametime'); } /** @@ -247,7 +245,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ unpauseGameTime() { - return this.send('unpausegametime', false); + return this.send('unpausegametime'); } /** @@ -256,7 +254,7 @@ class LiveSplitClient extends EventEmitter { * @returns {boolean} */ setComparison(comparison) { - return this.send(`setcomparison ${comparison}`, false); + return this.send('setcomparison', { comparison }); } /** @@ -265,8 +263,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getDelta(comparison = '') { - if (comparison) comparison = ` ${comparison}`; - return this.send(`getdelta${comparison}`, true); + return this.send('getdelta', { comparison }); } /** @@ -274,7 +271,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getLastSplitTime() { - return this.send('getlastsplittime', true); + return this.send('getlastsplittime'); } /** @@ -282,7 +279,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getComparisonSplitTime() { - return this.send('getcomparisonsplittime', true); + return this.send('getcomparisonsplittime'); } /** @@ -290,7 +287,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getCurrentTime() { - return this.send('getcurrenttime', true); + return this.send('getcurrenttime'); } /** @@ -299,8 +296,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getFinalTime(comparison = '') { - if (comparison) comparison = ` ${comparison}`; - return this.send(`getfinaltime${comparison}`, true); + return this.send('getfinaltime', { comparison }); } /** @@ -309,8 +305,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getPredictedTime(comparison = '') { - if (comparison) comparison = ` ${comparison}`; - return this.send(`getpredictedtime${comparison}`, true); + return this.send('getpredictedtime', { comparison }); } /** @@ -318,7 +313,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getBestPossibleTime() { - return this.send('getbestpossibletime', true); + return this.send('getbestpossibletime'); } /** @@ -326,7 +321,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getSplitIndex() { - return this.send('getsplitindex', true); + return this.send('getsplitindex'); } /** @@ -334,7 +329,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getCurrentSplitName() { - return this.send('getcurrentsplitname', true); + return this.send('getcurrentsplitname'); } /** @@ -342,7 +337,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getPreviousSplitName() { - return this.send('getprevioussplitname', true); + return this.send('getprevioussplitname'); } getPreviousSplitname() { @@ -354,7 +349,7 @@ class LiveSplitClient extends EventEmitter { * @returns {Promise} Command result or null on timeout. */ getCurrentTimerPhase() { - return this.send('getcurrenttimerphase', true); + return this.send('getcurrenttimerphase'); } /** From 4122afc8549ba7dab986f100413e89d94d9d7b7b Mon Sep 17 00:00:00 2001 From: Jeff Hobson Date: Thu, 10 Mar 2022 14:37:27 -0500 Subject: [PATCH 2/3] Update to new JSON messaging standard See https://github.com/LiveSplit/LiveSplit.Server/pull/39 for more details --- src/LiveSplitClient.js | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/LiveSplitClient.js b/src/LiveSplitClient.js index d937835..db781c3 100644 --- a/src/LiveSplitClient.js +++ b/src/LiveSplitClient.js @@ -117,7 +117,7 @@ class LiveSplitClient extends EventEmitter { const responseRecieved = new Promise((resolve) => { listener = (data) => { - resolve(data); + resolve(JSON.parse(data)); }; this.once('data', listener); @@ -142,7 +142,7 @@ class LiveSplitClient extends EventEmitter { /** * Start timer - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ startTimer() { return this.send('starttimer'); @@ -150,7 +150,7 @@ class LiveSplitClient extends EventEmitter { /** * Start or split - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ startOrSplit() { return this.send('startorsplit'); @@ -158,7 +158,7 @@ class LiveSplitClient extends EventEmitter { /** * Split - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ split() { return this.send('split'); @@ -166,7 +166,7 @@ class LiveSplitClient extends EventEmitter { /** * Unsplit - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ unsplit() { return this.send('unsplit'); @@ -174,7 +174,7 @@ class LiveSplitClient extends EventEmitter { /** * Skip split - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ skipSplit() { return this.send('skipsplit'); @@ -182,7 +182,7 @@ class LiveSplitClient extends EventEmitter { /** * Pause - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ pause() { return this.send('pause'); @@ -190,7 +190,7 @@ class LiveSplitClient extends EventEmitter { /** * Resume - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ resume() { return this.send('resume'); @@ -198,7 +198,7 @@ class LiveSplitClient extends EventEmitter { /** * Reset - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ reset() { return this.send('reset'); @@ -206,7 +206,7 @@ class LiveSplitClient extends EventEmitter { /** * Init game time. Could be called only once according to LiveSplit Server documentation. - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ initGameTime() { if (this._initGameTimeOnce) return false; @@ -217,7 +217,7 @@ class LiveSplitClient extends EventEmitter { /** * Set game time * @param {string} time - Game time - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ setGameTime(time) { return this.send('setgametime', { time }); @@ -226,7 +226,7 @@ class LiveSplitClient extends EventEmitter { /** * Set loading times * @param {string} time - Game time - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ setLoadingTimes(time) { return this.send('setloadingtimes', { time }); @@ -234,7 +234,7 @@ class LiveSplitClient extends EventEmitter { /** * Pause game time - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ pauseGameTime() { return this.send('pausegametime'); @@ -242,7 +242,7 @@ class LiveSplitClient extends EventEmitter { /** * Unpause game time - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ unpauseGameTime() { return this.send('unpausegametime'); @@ -251,7 +251,7 @@ class LiveSplitClient extends EventEmitter { /** * Set comparison * @param {string} comparison - Comparison - * @returns {boolean} + * @returns {Promise} Command result or null on timeout. */ setComparison(comparison) { return this.send('setcomparison', { comparison }); @@ -360,9 +360,8 @@ class LiveSplitClient extends EventEmitter { const output = {}; for (let method of ['getCurrentTimerPhase', 'getDelta', 'getLastSplitTime', 'getComparisonSplitTime', 'getCurrentTime', 'getFinalTime', 'getPredictedTime', 'getBestPossibleTime', 'getSplitIndex', 'getCurrentSplitName', 'getPreviousSplitName']) { - output[ - method.replace('get', '').charAt(0).toLowerCase() + method.replace('get', '').slice(1) - ] = await this[method](); + let response = await this[method](); + Object.assign(output, response.data); } return output; From 4559ebe5a7feaea79af77b3ae0ef1a50b15e81bf Mon Sep 17 00:00:00 2001 From: Jeff Hobson Date: Thu, 10 Mar 2022 14:38:16 -0500 Subject: [PATCH 3/3] Fix: Data event should handle accidental message concatenation At very fast polling intervals, the socket will sometimes send more than one message from the server in a single 'data' event. This change gracefully handles these edge cases, resulting in successful tests at as fast as polling every 5ms. --- src/LiveSplitClient.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/LiveSplitClient.js b/src/LiveSplitClient.js index db781c3..0dbb211 100644 --- a/src/LiveSplitClient.js +++ b/src/LiveSplitClient.js @@ -54,10 +54,13 @@ class LiveSplitClient extends EventEmitter { }); this._socket.on('data', (data) => { - this.emit( - 'data', - data.toString('utf-8').replace('\r\n', '') - ); + // This should catch edge cases where multiple messages are sent by the server + // so fast that this listener only fires once with all of them (concatenated). + // This allows for polling at a much faster rate with fewer errors. + const messages = data.toString('utf-8').split('\r\n'); + messages.forEach(message => { + this.emit('data', message); + }); }); this._socket.on('error', (err) => {