From 381a58bedce155a58aab203fa02f30283e77e64e Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 20 Feb 2024 05:27:42 -0800 Subject: [PATCH 01/18] WIP --- code/modules/tgui_panel/ping_relay.dm | 14 +++ code/modules/tgui_panel/tgui_panel.dm | 3 + colonialmarines.dme | 1 + tgui/packages/common/ping.js | 100 ++++++++++++++++++ .../packages/tgui-panel/ping/PingIndicator.js | 16 ++- .../tgui/interfaces/PingRelaysPanel.jsx | 88 +++++++++++++++ 6 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 code/modules/tgui_panel/ping_relay.dm create mode 100644 tgui/packages/common/ping.js create mode 100644 tgui/packages/tgui/interfaces/PingRelaysPanel.jsx diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm new file mode 100644 index 000000000000..ff585b9fd998 --- /dev/null +++ b/code/modules/tgui_panel/ping_relay.dm @@ -0,0 +1,14 @@ +GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) + +/datum/tgui_panel/proc/ping_relays() + GLOB.relays_panel.tgui_interact(client.mob) + +/datum/ping_relay_tgui/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PingRelaysPanel", "Relay Pings") + ui.open() + //ui.set_autoupdate(FALSE) + +/datum/ping_relay_tgui/ui_state(mob/user) + return GLOB.always_state diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm index f33f190d80e0..25338a4a3b5d 100644 --- a/code/modules/tgui_panel/tgui_panel.dm +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -92,6 +92,9 @@ if(type == "telemetry") analyze_telemetry(payload) return TRUE + if(type == "act/ping_relays") + ping_relays() + return TRUE /** * public diff --git a/colonialmarines.dme b/colonialmarines.dme index f3dc6f1f81d9..294b960e7668 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -2356,6 +2356,7 @@ #include "code\modules\tgui_input\text.dm" #include "code\modules\tgui_panel\audio.dm" #include "code\modules\tgui_panel\external.dm" +#include "code\modules\tgui_panel\ping_relay.dm" #include "code\modules\tgui_panel\telemetry.dm" #include "code\modules\tgui_panel\tgui_panel.dm" #include "code\modules\tooltip\tooltip.dm" diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js new file mode 100644 index 000000000000..8e66aa50d4de --- /dev/null +++ b/tgui/packages/common/ping.js @@ -0,0 +1,100 @@ +/** + * @file https://www.jsdelivr.com/package/npm/ping.js?tab=files&version=0.3.0&path=src + * @copyright 2021 Alfred Gutierrez + * @license MIT + */ + +/** + * Creates a Ping instance. + * @returns {Ping} + * @constructor + */ +export class Ping { + constructor(opt) { + this.opt = opt || {}; + this.favicon = this.opt.favicon || '/favicon.ico'; + this.timeout = this.opt.timeout || 0; + this.logError = this.opt.logError || false; + } + /** + * Pings source and triggers a callback when completed. + * @param {string} source Source of the website or server, including protocol and port. + * @param {Function} callback Callback function to trigger when completed. Returns error and ping value. + * @returns {Promise|undefined} A promise that both resolves and rejects to the ping value. Or undefined if the browser does not support Promise. + */ + ping(source, callback) { + let promise, resolve, reject; + if (typeof Promise !== 'undefined') { + promise = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; + }); + } + + let self = this; + self.wasSuccess = false; + self.img = new Image(); + self.img.onload = onload; + self.img.onerror = onerror; + + let timer; + let start = new Date(); + + const onload = function (e) { + self.wasSuccess = true; + pingCheck.call(self, e); + }; + + const onerror = function (e) { + self.wasSuccess = false; + pingCheck.call(self, e); + }; + + if (self.timeout) { + timer = setTimeout(() => { + pingCheck.call(self, undefined); + }, self.timeout); + } + + /** + * Times ping and triggers callback. + */ + const pingCheck = function () { + if (timer) { + clearTimeout(timer); + } + let pong = new Date() - start; + + if (!callback) { + if (promise) { + return this.wasSuccess ? resolve(pong) : reject(pong); + } else { + throw new Error( + 'Promise is not supported by your browser. Use callback instead.' + ); + } + } else if (typeof callback === 'function') { + // When operating in timeout mode, the timeout callback doesn't pass [event] as e. + // Notice [this] instead of [self], since .call() was used with context + if (!this.wasSuccess) { + if (self.logError) { + console.error('error loading resource'); + } + if (promise) { + reject(pong); + } + return callback('error', pong); + } + if (promise) { + resolve(pong); + } + return callback(null, pong); + } else { + throw new Error('Callback is not a function.'); + } + }; + + self.img.src = source + self.favicon + '?' + +new Date(); // Trigger image load with cache buster + return promise; + } +} diff --git a/tgui/packages/tgui-panel/ping/PingIndicator.js b/tgui/packages/tgui-panel/ping/PingIndicator.js index b2355820e58a..ce98d5dca1ba 100644 --- a/tgui/packages/tgui-panel/ping/PingIndicator.js +++ b/tgui/packages/tgui-panel/ping/PingIndicator.js @@ -6,11 +6,12 @@ import { Color } from 'common/color'; import { toFixed } from 'common/math'; -import { useSelector } from 'tgui/backend'; -import { Box } from 'tgui/components'; +import { useSelector, useBackend } from 'tgui/backend'; +import { Button, Box } from 'tgui/components'; import { selectPing } from './selectors'; export const PingIndicator = (props) => { + const { act } = useBackend(); const ping = useSelector(selectPing); const color = Color.lookup(ping.networkQuality, [ new Color(220, 40, 40), @@ -19,9 +20,16 @@ export const PingIndicator = (props) => { ]); const roundtrip = ping.roundtrip ? toFixed(ping.roundtrip) : '--'; return ( -
+
+ ); }; diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx new file mode 100644 index 000000000000..dd0b12eb53a8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -0,0 +1,88 @@ +import { Stack } from '../components'; +import { Window } from '../layouts'; +import { Color } from 'common/color'; +import { Ping } from 'common/ping'; + +const COLORS = [ + new Color(220, 40, 40), // red + new Color(220, 200, 40), // yellow + new Color(60, 220, 40), // green +]; + +const getPingColor = function (ping) { + if (ping < 100) { + return COLORS[2]; + } + if (ping < 400) { + return COLORS[1]; + } + return COLORS[0]; +}; + +export class PingResult { + constructor(desc = 'Loading...', url = '', ping = 0, color = COLORS[0]) { + this.desc = desc; + this.url = url; + this.ping = ping; + this.color = color; + } + + update(desc, url, ping) { + this.desc = desc; + this.url = url; + this.ping = ping; + this.color = getPingColor(ping); + } +} + +let p = new Ping(); +let currentIndex = 0; +let results = Array(8).fill(new PingResult()); + +const startTest = function (desc, pingURL, connectURL) { + p.ping(`http://${pingURL}`, (err, data) => { + results[++currentIndex].update(desc, `byond://${connectURL}`, data); + }); +}; + +startTest('Direct', 'play.cm-ss13.com:8998', 'play.cm-ss13.com:1400'); +startTest( + 'United Kingdom, London', + 'uk.cm-ss13.com:8998', + 'uk.cm-ss13.com:1400' +); +startTest( + 'France, Gravelines', + 'eu-w.cm-ss13.com:8998', + 'eu-w.cm-ss13.com:1400' +); +startTest('Poland, Warsaw', 'eu-e.cm-ss13.com:8998', 'eu-e.cm-ss13.com:1400'); +startTest( + 'Oregon, Hillsboro', + 'us-w.cm-ss13.com:8998', + 'us-w.cm-ss13.com:1400' +); +startTest( + 'Virginia, Vint Hill', + 'us-e.cm-ss13.com:8998', + 'us-e.cm-ss13.com:1400' +); +startTest('Singapore', 'asia-se.cm-ss13.com:8998', 'asia-se.cm-ss13.com:1400'); +startTest('Australia, Sydney', 'aus.cm-ss13.com:8998', 'aus.cm-ss13.com:1400'); + +export const PingRelaysPanel = () => { + return ( + + + + {results.map((result, i) => ( + + {result.desc}: {result.url}{' '} + ({result.ping}) + + ))} + + + + ); +}; From 94b7ed73fc4955e1fcf6a9fd8a4f24fcd9e03d26 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 20 Feb 2024 06:17:12 -0800 Subject: [PATCH 02/18] WIP 2 --- tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index dd0b12eb53a8..2985317f8a19 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -1,7 +1,10 @@ -import { Stack } from '../components'; +import { Box, Stack } from '../components'; import { Window } from '../layouts'; import { Color } from 'common/color'; import { Ping } from 'common/ping'; +import { createLogger } from '../logging'; // TODO: Remove this + +const logger = createLogger('pingRelays'); // TODO: Remove this const COLORS = [ new Color(220, 40, 40), // red @@ -37,11 +40,16 @@ export class PingResult { let p = new Ping(); let currentIndex = 0; -let results = Array(8).fill(new PingResult()); +let results = new Array(8); +for (let i = 0; i < 8; i++) { + results[i] = new PingResult(); +} const startTest = function (desc, pingURL, connectURL) { + logger.log('starting test for ' + desc); // TODO: Remove this p.ping(`http://${pingURL}`, (err, data) => { results[++currentIndex].update(desc, `byond://${connectURL}`, data); + logger.log('finished ' + currentIndex + ' ' + data + ' ' + err); // TODO: Remove this }); }; @@ -78,7 +86,7 @@ export const PingRelaysPanel = () => { {results.map((result, i) => ( {result.desc}: {result.url}{' '} - ({result.ping}) + ({result.ping}) ))} From a062d42b6d2bd2f6c0caae4bc1ec971b53edb857 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 20 Feb 2024 07:22:26 -0800 Subject: [PATCH 03/18] Fix templated strings --- code/modules/tgui_panel/ping_relay.dm | 2 +- tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index ff585b9fd998..df0c74a9436a 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -8,7 +8,7 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) if(!ui) ui = new(user, src, "PingRelaysPanel", "Relay Pings") ui.open() - //ui.set_autoupdate(FALSE) + ui.set_autoupdate(FALSE) /datum/ping_relay_tgui/ui_state(mob/user) return GLOB.always_state diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 2985317f8a19..6c51b624b54b 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -47,8 +47,8 @@ for (let i = 0; i < 8; i++) { const startTest = function (desc, pingURL, connectURL) { logger.log('starting test for ' + desc); // TODO: Remove this - p.ping(`http://${pingURL}`, (err, data) => { - results[++currentIndex].update(desc, `byond://${connectURL}`, data); + p.ping('http://' + pingURL, (err, data) => { + results[++currentIndex].update(desc, 'byond://' + connectURL, data); logger.log('finished ' + currentIndex + ' ' + data + ' ' + err); // TODO: Remove this }); }; From 24e9ab5a7dc242375d009113883d0bf44c971051 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 20 Feb 2024 18:24:13 -0800 Subject: [PATCH 04/18] Still broken --- code/modules/tgui_panel/ping_relay.dm | 2 +- tgui/packages/common/ping.js | 2 +- tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index df0c74a9436a..ff585b9fd998 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -8,7 +8,7 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) if(!ui) ui = new(user, src, "PingRelaysPanel", "Relay Pings") ui.open() - ui.set_autoupdate(FALSE) + //ui.set_autoupdate(FALSE) /datum/ping_relay_tgui/ui_state(mob/user) return GLOB.always_state diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js index 8e66aa50d4de..b75a8bc70d6f 100644 --- a/tgui/packages/common/ping.js +++ b/tgui/packages/common/ping.js @@ -13,7 +13,7 @@ export class Ping { constructor(opt) { this.opt = opt || {}; this.favicon = this.opt.favicon || '/favicon.ico'; - this.timeout = this.opt.timeout || 0; + this.timeout = this.opt.timeout || 10000; this.logError = this.opt.logError || false; } /** diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 6c51b624b54b..f954882d4a43 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -30,12 +30,12 @@ export class PingResult { this.color = color; } - update(desc, url, ping) { + update = function (desc, url, ping) { this.desc = desc; this.url = url; this.ping = ping; this.color = getPingColor(ping); - } + }; } let p = new Ping(); @@ -48,7 +48,7 @@ for (let i = 0; i < 8; i++) { const startTest = function (desc, pingURL, connectURL) { logger.log('starting test for ' + desc); // TODO: Remove this p.ping('http://' + pingURL, (err, data) => { - results[++currentIndex].update(desc, 'byond://' + connectURL, data); + results[currentIndex++].update(desc, 'byond://' + connectURL, data); logger.log('finished ' + currentIndex + ' ' + data + ' ' + err); // TODO: Remove this }); }; From d966e6d2ce3e85aa21ed31b0b60a70907c5bf06b Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 20 Feb 2024 18:52:02 -0800 Subject: [PATCH 05/18] Remove promise support --- tgui/packages/common/ping.js | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js index b75a8bc70d6f..6a3ee927abee 100644 --- a/tgui/packages/common/ping.js +++ b/tgui/packages/common/ping.js @@ -1,5 +1,5 @@ /** - * @file https://www.jsdelivr.com/package/npm/ping.js?tab=files&version=0.3.0&path=src + * @file https://www.jsdelivr.com/package/npm/ping.js * @copyright 2021 Alfred Gutierrez * @license MIT */ @@ -13,24 +13,16 @@ export class Ping { constructor(opt) { this.opt = opt || {}; this.favicon = this.opt.favicon || '/favicon.ico'; - this.timeout = this.opt.timeout || 10000; + this.timeout = this.opt.timeout || 5000; this.logError = this.opt.logError || false; } /** * Pings source and triggers a callback when completed. - * @param {string} source Source of the website or server, including protocol and port. - * @param {Function} callback Callback function to trigger when completed. Returns error and ping value. - * @returns {Promise|undefined} A promise that both resolves and rejects to the ping value. Or undefined if the browser does not support Promise. + * @param source Source of the website or server, including protocol and port. + * @param callback Callback function to trigger when completed. Returns error and ping value. + * @param timeout Optional number of milliseconds to wait before aborting. */ ping(source, callback) { - let promise, resolve, reject; - if (typeof Promise !== 'undefined') { - promise = new Promise((_resolve, _reject) => { - resolve = _resolve; - reject = _reject; - }); - } - let self = this; self.wasSuccess = false; self.img = new Image(); @@ -65,29 +57,15 @@ export class Ping { } let pong = new Date() - start; - if (!callback) { - if (promise) { - return this.wasSuccess ? resolve(pong) : reject(pong); - } else { - throw new Error( - 'Promise is not supported by your browser. Use callback instead.' - ); - } - } else if (typeof callback === 'function') { + if (typeof callback === 'function') { // When operating in timeout mode, the timeout callback doesn't pass [event] as e. // Notice [this] instead of [self], since .call() was used with context if (!this.wasSuccess) { if (self.logError) { console.error('error loading resource'); } - if (promise) { - reject(pong); - } return callback('error', pong); } - if (promise) { - resolve(pong); - } return callback(null, pong); } else { throw new Error('Callback is not a function.'); @@ -95,6 +73,5 @@ export class Ping { }; self.img.src = source + self.favicon + '?' + +new Date(); // Trigger image load with cache buster - return promise; } } From a598709fff6013851dc4b5ce34cb024bb76eb6f4 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 20 Feb 2024 20:37:33 -0800 Subject: [PATCH 06/18] Finally calls onload --- tgui/packages/common/ping.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js index 6a3ee927abee..e36ef9727b43 100644 --- a/tgui/packages/common/ping.js +++ b/tgui/packages/common/ping.js @@ -26,22 +26,18 @@ export class Ping { let self = this; self.wasSuccess = false; self.img = new Image(); - self.img.onload = onload; - self.img.onerror = onerror; - - let timer; - let start = new Date(); - - const onload = function (e) { + self.img.onload = (e) => { self.wasSuccess = true; pingCheck.call(self, e); }; - - const onerror = function (e) { + self.img.onerror = (e) => { self.wasSuccess = false; pingCheck.call(self, e); }; + let timer; + let start = new Date(); + if (self.timeout) { timer = setTimeout(() => { pingCheck.call(self, undefined); From 54b294ebb0e6937ade1e33f11bb2c186671bc794 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 21 Feb 2024 05:18:13 -0800 Subject: [PATCH 07/18] Finally functional --- code/modules/tgui_panel/ping_relay.dm | 2 +- tgui/packages/common/ping.js | 29 +++- .../tgui/interfaces/PingRelaysPanel.jsx | 134 ++++++++++++------ 3 files changed, 111 insertions(+), 54 deletions(-) diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index ff585b9fd998..df0c74a9436a 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -8,7 +8,7 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) if(!ui) ui = new(user, src, "PingRelaysPanel", "Relay Pings") ui.open() - //ui.set_autoupdate(FALSE) + ui.set_autoupdate(FALSE) /datum/ping_relay_tgui/ui_state(mob/user) return GLOB.always_state diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js index e36ef9727b43..3a843aafc9ad 100644 --- a/tgui/packages/common/ping.js +++ b/tgui/packages/common/ping.js @@ -1,4 +1,5 @@ /** + * Adapted pinging library based on: * @file https://www.jsdelivr.com/package/npm/ping.js * @copyright 2021 Alfred Gutierrez * @license MIT @@ -13,16 +14,29 @@ export class Ping { constructor(opt) { this.opt = opt || {}; this.favicon = this.opt.favicon || '/favicon.ico'; - this.timeout = this.opt.timeout || 5000; + this.timeout = this.opt.timeout || 10000; this.logError = this.opt.logError || false; } + + /** + * Pings source after a delay and triggers a callback when completed. + * @param source Source of the website or server, including protocol and port. + * @param callback Callback function to trigger when completed. Returns error and ping value. + * @param delay Optional number of milliseconds to wait before starting. + */ + ping(source, callback, delay = 500) { + let timer; + timer = setTimeout(() => { + this.pingNow(source, callback); + }, delay); + } + /** - * Pings source and triggers a callback when completed. + * Pings source immediately and triggers a callback when completed. * @param source Source of the website or server, including protocol and port. * @param callback Callback function to trigger when completed. Returns error and ping value. - * @param timeout Optional number of milliseconds to wait before aborting. */ - ping(source, callback) { + pingNow(source, callback) { let self = this; self.wasSuccess = false; self.img = new Image(); @@ -40,6 +54,7 @@ export class Ping { if (self.timeout) { timer = setTimeout(() => { + self.wasSuccess = false; pingCheck.call(self, undefined); }, self.timeout); } @@ -47,7 +62,7 @@ export class Ping { /** * Times ping and triggers callback. */ - const pingCheck = function () { + const pingCheck = function (e) { if (timer) { clearTimeout(timer); } @@ -58,9 +73,9 @@ export class Ping { // Notice [this] instead of [self], since .call() was used with context if (!this.wasSuccess) { if (self.logError) { - console.error('error loading resource'); + console.error('error loading resource: ' + e.error); } - return callback('error', pong); + return callback(e ? 'error' : 'timeout', pong); } return callback(null, pong); } else { diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index f954882d4a43..c5b2a9c3a679 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -2,10 +2,13 @@ import { Box, Stack } from '../components'; import { Window } from '../layouts'; import { Color } from 'common/color'; import { Ping } from 'common/ping'; +import { Component } from 'react'; import { createLogger } from '../logging'; // TODO: Remove this const logger = createLogger('pingRelays'); // TODO: Remove this +const RELAY_COUNT = 8; + const COLORS = [ new Color(220, 40, 40), // red new Color(220, 200, 40), // yellow @@ -28,68 +31,107 @@ export class PingResult { this.url = url; this.ping = ping; this.color = color; + this.error = null; } - update = function (desc, url, ping) { + update = function (desc, url, ping, error) { this.desc = desc; this.url = url; this.ping = ping; this.color = getPingColor(ping); + this.error = error; }; } -let p = new Ping(); -let currentIndex = 0; -let results = new Array(8); -for (let i = 0; i < 8; i++) { - results[i] = new PingResult(); -} +class PingApp extends Component { + constructor() { + super(); -const startTest = function (desc, pingURL, connectURL) { - logger.log('starting test for ' + desc); // TODO: Remove this - p.ping('http://' + pingURL, (err, data) => { - results[currentIndex++].update(desc, 'byond://' + connectURL, data); - logger.log('finished ' + currentIndex + ' ' + data + ' ' + err); // TODO: Remove this - }); -}; + this.pinger = new Ping(); + this.state = { currentIndex: 0 }; -startTest('Direct', 'play.cm-ss13.com:8998', 'play.cm-ss13.com:1400'); -startTest( - 'United Kingdom, London', - 'uk.cm-ss13.com:8998', - 'uk.cm-ss13.com:1400' -); -startTest( - 'France, Gravelines', - 'eu-w.cm-ss13.com:8998', - 'eu-w.cm-ss13.com:1400' -); -startTest('Poland, Warsaw', 'eu-e.cm-ss13.com:8998', 'eu-e.cm-ss13.com:1400'); -startTest( - 'Oregon, Hillsboro', - 'us-w.cm-ss13.com:8998', - 'us-w.cm-ss13.com:1400' -); -startTest( - 'Virginia, Vint Hill', - 'us-e.cm-ss13.com:8998', - 'us-e.cm-ss13.com:1400' -); -startTest('Singapore', 'asia-se.cm-ss13.com:8998', 'asia-se.cm-ss13.com:1400'); -startTest('Australia, Sydney', 'aus.cm-ss13.com:8998', 'aus.cm-ss13.com:1400'); + this.results = new Array(RELAY_COUNT); + for (let i = 0; i < RELAY_COUNT; i++) { + this.results[i] = new PingResult(); + } + } + + startTest(desc, pingURL, connectURL) { + logger.log('starting test for ' + desc); // TODO: Remove this + this.pinger.ping('http://' + pingURL, (error, pong) => { + this.results[this.state.currentIndex]?.update( + desc, + 'byond://' + connectURL, + pong, + error + ); + logger.log( + 'finished ' + this.state.currentIndex + ' ' + pong + ' ' + error + ); // TODO: Remove this + this.setState((prevState) => ({ + currentIndex: prevState.currentIndex + 1, + })); + }); + } + + componentDidMount() { + this.startTest('Direct', 'play.cm-ss13.com:8998', 'play.cm-ss13.com:1400'); + this.startTest( + 'United Kingdom, London', + 'uk.cm-ss13.com:8998', + 'uk.cm-ss13.com:1400' + ); + this.startTest( + 'France, Gravelines', + 'eu-w.cm-ss13.com:8998', + 'eu-w.cm-ss13.com:1400' + ); + this.startTest( + 'Poland, Warsaw', + 'eu-e.cm-ss13.com:8998', + 'eu-e.cm-ss13.com:1400' + ); + this.startTest( + 'Oregon, Hillsboro', + 'us-w.cm-ss13.com:8998', + 'us-w.cm-ss13.com:1400' + ); + this.startTest( + 'Virginia, Vint Hill', + 'us-e.cm-ss13.com:8998', + 'us-e.cm-ss13.com:1400' + ); + this.startTest( + 'Singapore', + 'asia-se.cm-ss13.com:8998', + 'asia-se.cm-ss13.com:1400' + ); + this.startTest( + 'Australia, Sydney', + 'aus.cm-ss13.com:8996', // wrong + 'aus.cm-ss13.com:1400' + ); + } + + render() { + return ( + + {this.results.map((result, i) => ( + + {result.desc}: {result.url}{' '} + ({result.ping}) {result.error} + + ))} + + ); + } +} export const PingRelaysPanel = () => { return ( - - {results.map((result, i) => ( - - {result.desc}: {result.url}{' '} - ({result.ping}) - - ))} - + ); From a95cddc15cb0a08972afd93d6e954c0e2f0d652c Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 21 Feb 2024 07:17:22 -0800 Subject: [PATCH 08/18] Polish --- code/modules/tgui_panel/ping_relay.dm | 13 +++++ tgui/packages/common/ping.js | 4 +- .../tgui/interfaces/PingRelaysPanel.jsx | 54 ++++++++++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index df0c74a9436a..8bff79fa14f6 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -12,3 +12,16 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) /datum/ping_relay_tgui/ui_state(mob/user) return GLOB.always_state + +/datum/ping_relay_tgui/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/mob/user = ui.user + + switch(action) + if("connect") + user << link(params["url"]) + ui.close() + return diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js index 3a843aafc9ad..002925ffc280 100644 --- a/tgui/packages/common/ping.js +++ b/tgui/packages/common/ping.js @@ -24,7 +24,7 @@ export class Ping { * @param callback Callback function to trigger when completed. Returns error and ping value. * @param delay Optional number of milliseconds to wait before starting. */ - ping(source, callback, delay = 500) { + ping(source, callback, delay = 1000) { let timer; timer = setTimeout(() => { this.pingNow(source, callback); @@ -75,7 +75,7 @@ export class Ping { if (self.logError) { console.error('error loading resource: ' + e.error); } - return callback(e ? 'error' : 'timeout', pong); + return callback(e ? 'Error' : 'Timed Out', pong); } return callback(null, pong); } else { diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index c5b2a9c3a679..3a33f9d29503 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -1,11 +1,9 @@ -import { Box, Stack } from '../components'; +import { useBackend } from '../backend'; +import { Box, Stack, Button, Icon } from '../components'; import { Window } from '../layouts'; import { Color } from 'common/color'; import { Ping } from 'common/ping'; import { Component } from 'react'; -import { createLogger } from '../logging'; // TODO: Remove this - -const logger = createLogger('pingRelays'); // TODO: Remove this const RELAY_COUNT = 8; @@ -26,7 +24,7 @@ const getPingColor = function (ping) { }; export class PingResult { - constructor(desc = 'Loading...', url = '', ping = 0, color = COLORS[0]) { + constructor(desc = 'Loading...', url = '', ping = -1, color = COLORS[0]) { this.desc = desc; this.url = url; this.ping = ping; @@ -57,7 +55,6 @@ class PingApp extends Component { } startTest(desc, pingURL, connectURL) { - logger.log('starting test for ' + desc); // TODO: Remove this this.pinger.ping('http://' + pingURL, (error, pong) => { this.results[this.state.currentIndex]?.update( desc, @@ -65,9 +62,6 @@ class PingApp extends Component { pong, error ); - logger.log( - 'finished ' + this.state.currentIndex + ' ' + pong + ' ' + error - ); // TODO: Remove this this.setState((prevState) => ({ currentIndex: prevState.currentIndex + 1, })); @@ -114,12 +108,44 @@ class PingApp extends Component { } render() { + const { act } = useBackend(); + return ( - + {this.results.map((result, i) => ( - - {result.desc}: {result.url}{' '} - ({result.ping}) {result.error} + + act('connect', { url: result.url })}> + {result.ping <= -1 && result.error === null && ( + <> + + {result.desc} + + )} + {result.ping > -1 && result.error === null && ( + <> + + {result.desc} + + {' (' + result.ping + ')'} + + + )} + {result.error !== null && ( + <> + + {result.desc} + + {' (' + result.error + ')'} + + + )} + ))} @@ -129,7 +155,7 @@ class PingApp extends Component { export const PingRelaysPanel = () => { return ( - + From 7385ff6e35a626693e4968041d7cc790fd4baea0 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 21 Feb 2024 07:24:47 -0800 Subject: [PATCH 09/18] Correct testing edit --- tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 3a33f9d29503..d493d0e9ae9f 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -102,7 +102,7 @@ class PingApp extends Component { ); this.startTest( 'Australia, Sydney', - 'aus.cm-ss13.com:8996', // wrong + 'aus.cm-ss13.com:8998', 'aus.cm-ss13.com:1400' ); } From 994053e241eb09b0cc5eab8d8b92f5b90266c207 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 21 Feb 2024 07:28:54 -0800 Subject: [PATCH 10/18] Tweak color thresholds --- tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index d493d0e9ae9f..ae301ea3833f 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -14,10 +14,10 @@ const COLORS = [ ]; const getPingColor = function (ping) { - if (ping < 100) { + if (ping < 200) { return COLORS[2]; } - if (ping < 400) { + if (ping < 500) { return COLORS[1]; } return COLORS[0]; From 21d5e29a3dfbee1229a76f355680648ce5c5a953 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 21 Feb 2024 08:35:41 -0800 Subject: [PATCH 11/18] Gauges? --- .../tgui/interfaces/PingRelaysPanel.jsx | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index ae301ea3833f..4fc528e97258 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -1,34 +1,18 @@ import { useBackend } from '../backend'; -import { Box, Stack, Button, Icon } from '../components'; +import { Box, Stack, Button, Icon, RoundGauge } from '../components'; import { Window } from '../layouts'; import { Color } from 'common/color'; import { Ping } from 'common/ping'; import { Component } from 'react'; const RELAY_COUNT = 8; - -const COLORS = [ - new Color(220, 40, 40), // red - new Color(220, 200, 40), // yellow - new Color(60, 220, 40), // green -]; - -const getPingColor = function (ping) { - if (ping < 200) { - return COLORS[2]; - } - if (ping < 500) { - return COLORS[1]; - } - return COLORS[0]; -}; +const RED = new Color(220, 40, 40); export class PingResult { - constructor(desc = 'Loading...', url = '', ping = -1, color = COLORS[0]) { + constructor(desc = 'Loading...', url = '', ping = -1) { this.desc = desc; this.url = url; this.ping = ping; - this.color = color; this.error = null; } @@ -36,7 +20,6 @@ export class PingResult { this.desc = desc; this.url = url; this.ping = ping; - this.color = getPingColor(ping); this.error = error; }; } @@ -130,17 +113,28 @@ class PingApp extends Component { {result.ping > -1 && result.error === null && ( <> - {result.desc} - - {' (' + result.ping + ')'} + + {result.desc + ' '} + ' ' + x + 'ms'} + inline + /> )} {result.error !== null && ( <> - + {result.desc} - + {' (' + result.error + ')'} From 2340050ccb22c0f03e20b974d1defbcea8ba46d1 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 22 Feb 2024 13:08:36 -0800 Subject: [PATCH 12/18] Add onConfirmChange callback prop to Button.Confirm Update layout Refactoring --- tgui/docs/component-reference.md | 1 + .../packages/tgui-panel/ping/PingIndicator.js | 3 + tgui/packages/tgui/components/Button.jsx | 4 + .../tgui/interfaces/PingRelaysPanel.jsx | 99 +++++++++++++------ 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md index d814fc343a72..3789016447cc 100644 --- a/tgui/docs/component-reference.md +++ b/tgui/docs/component-reference.md @@ -250,6 +250,7 @@ A button with an extra confirmation step, using native button component. - See inherited props: [Button](#button) - `confirmContent: string` - Text to display after first click; defaults to "Confirm?" - `confirmColor: string` - Color to display after first click; defaults to "bad" +- `onConfirmChange: function` - Called when the clickedOnce state changes: When the element is clicked the first time or unfocused. ### `Button.Input` diff --git a/tgui/packages/tgui-panel/ping/PingIndicator.js b/tgui/packages/tgui-panel/ping/PingIndicator.js index ce98d5dca1ba..4e64207d115c 100644 --- a/tgui/packages/tgui-panel/ping/PingIndicator.js +++ b/tgui/packages/tgui-panel/ping/PingIndicator.js @@ -25,6 +25,9 @@ export const PingIndicator = (props) => { width="50px" className="Ping" color="transparent" + hover + py="0.125em" // Override what light theme does to this + px="0.25em" // Override what light theme does to this tooltip="Ping relays" tooltipPosition="bottom-start" onClick={() => act('ping_relays')}> diff --git a/tgui/packages/tgui/components/Button.jsx b/tgui/packages/tgui/components/Button.jsx index 4264b0767115..dbffb6a72c95 100644 --- a/tgui/packages/tgui/components/Button.jsx +++ b/tgui/packages/tgui/components/Button.jsx @@ -172,6 +172,9 @@ export class ButtonConfirm extends Component { } else { window.removeEventListener('click', this.handleClick); } + if (this.props.onConfirmChange) { + this.props.onConfirmChange(clickedOnce); + } } render() { @@ -183,6 +186,7 @@ export class ButtonConfirm extends Component { color, content, onClick, + onConfirmChange, ...rest } = this.props; return ( diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 4fc528e97258..09356f5c38bf 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -1,5 +1,5 @@ import { useBackend } from '../backend'; -import { Box, Stack, Button, Icon, RoundGauge } from '../components'; +import { Box, Stack, Button, Icon, RoundGauge, Flex } from '../components'; import { Window } from '../layouts'; import { Color } from 'common/color'; import { Ping } from 'common/ping'; @@ -29,7 +29,11 @@ class PingApp extends Component { super(); this.pinger = new Ping(); - this.state = { currentIndex: 0 }; + this.state = { + currentIndex: 0, + lastClickedIndex: 0, + lastClickedState: false, + }; this.results = new Array(RELAY_COUNT); for (let i = 0; i < RELAY_COUNT; i++) { @@ -51,6 +55,13 @@ class PingApp extends Component { }); } + handleConfirmChange(index, newState) { + if (newState || this.state.lastClickedIndex === index) { + this.setState({ lastClickedIndex: index }); + this.setState({ lastClickedState: newState }); + } + } + componentDidMount() { this.startTest('Direct', 'play.cm-ss13.com:8998', 'play.cm-ss13.com:1400'); this.startTest( @@ -100,44 +111,68 @@ class PingApp extends Component { + this.handleConfirmChange(i, clickedOnce) + } onClick={() => act('connect', { url: result.url })}> {result.ping <= -1 && result.error === null && ( - <> - - {result.desc} - + + + + + + {result.desc} + + + )} {result.ping > -1 && result.error === null && ( - <> - - - {result.desc + ' '} - - ' ' + x + 'ms'} - inline - /> - + + + + + + + {this.state.lastClickedIndex === i && + this.state.lastClickedState + ? 'Connect via ' + result.desc + '?' + : result.desc} + + + + x + 'ms'} + inline + /> + + )} {result.error !== null && ( - <> - - {result.desc} - - {' (' + result.error + ')'} - - + + + + + + {result.desc} + + + + {' (' + result.error + ')'} + + + )} From 979ed49432c3366e853ba79137bab572cfd2ef19 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 22 Feb 2024 13:10:22 -0800 Subject: [PATCH 13/18] Add abort functionality to ping to early return if the component is unmounted before a ping is started or finished --- tgui/packages/common/ping.js | 26 ++++++++++++++++--- .../tgui/interfaces/PingRelaysPanel.jsx | 4 +++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tgui/packages/common/ping.js b/tgui/packages/common/ping.js index 002925ffc280..e8f52882b6ae 100644 --- a/tgui/packages/common/ping.js +++ b/tgui/packages/common/ping.js @@ -16,6 +16,7 @@ export class Ping { this.favicon = this.opt.favicon || '/favicon.ico'; this.timeout = this.opt.timeout || 10000; this.logError = this.opt.logError || false; + this.abort = false; } /** @@ -25,10 +26,18 @@ export class Ping { * @param delay Optional number of milliseconds to wait before starting. */ ping(source, callback, delay = 1000) { + this.abort = false; let timer; - timer = setTimeout(() => { - this.pingNow(source, callback); - }, delay); + if (delay > 0) { + timer = setTimeout(() => { + if (this.abort) { + return; + } + this.pingNow(source, callback); + }, delay); + return; + } + this.pingNow(source, callback); } /** @@ -38,6 +47,7 @@ export class Ping { */ pingNow(source, callback) { let self = this; + self.abort = false; self.wasSuccess = false; self.img = new Image(); self.img.onload = (e) => { @@ -66,6 +76,9 @@ export class Ping { if (timer) { clearTimeout(timer); } + if (this.abort) { + return; + } let pong = new Date() - start; if (typeof callback === 'function') { @@ -85,4 +98,11 @@ export class Ping { self.img.src = source + self.favicon + '?' + +new Date(); // Trigger image load with cache buster } + + /** + * Aborts any pending ping request. + */ + cancel() { + this.abort = true; + } } diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 09356f5c38bf..03dadfe4ee5a 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -101,6 +101,10 @@ class PingApp extends Component { ); } + componentWillUnmount() { + this.pinger.cancel(); + } + render() { const { act } = useBackend(); From 7209b6df885d0e501db4c30bb679ce00cd479d5b Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 22 Feb 2024 13:11:36 -0800 Subject: [PATCH 14/18] De-inflate ping reported to bring it closer to value tgchat will report --- tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 03dadfe4ee5a..48f672ee77c1 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -1,4 +1,5 @@ import { useBackend } from '../backend'; +import { round } from 'common/math'; import { Box, Stack, Button, Icon, RoundGauge, Flex } from '../components'; import { Window } from '../layouts'; import { Color } from 'common/color'; @@ -46,7 +47,7 @@ class PingApp extends Component { this.results[this.state.currentIndex]?.update( desc, 'byond://' + connectURL, - pong, + round(pong * 0.75), // The ping is inflated so lets compensate a bit error ); this.setState((prevState) => ({ From 7bdd18ee8aaa1685ec5342010a52a2495d02463a Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 22 Feb 2024 15:15:33 -0800 Subject: [PATCH 15/18] Relay configs --- .../controllers/configuration/config_entry.dm | 5 +- .../configuration/entries/general.dm | 13 ++++ code/modules/tgui_panel/ping_relay.dm | 19 ++++++ config/example/config.txt | 1 + config/example/relays.txt | 22 +++++++ .../tgui/interfaces/PingRelaysPanel.jsx | 61 ++++++------------- 6 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 config/example/relays.txt diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index c47531f5fc45..2cc5107fdbc8 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -137,6 +137,7 @@ var/key_mode var/value_mode var/splitter = " " + var/to_lower_keys = TRUE /datum/config_entry/keyed_list/New() . = ..() @@ -153,7 +154,9 @@ var/key_value = null if(key_pos || value_mode == VALUE_MODE_FLAG) - key_name = lowertext(copytext(str_val, 1, key_pos)) + key_name = copytext(str_val, 1, key_pos) + if(to_lower_keys) + key_name = lowertext(key_name) if(key_pos) key_value = copytext(str_val, key_pos + length(str_val[key_pos])) var/new_key diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 83929ecf8803..1a374f7180f3 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -629,3 +629,16 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/flag/guest_ban /datum/config_entry/flag/auto_profile + +/// Relay Ping Browser configuration +/datum/config_entry/keyed_list/connection_relay_ping + splitter = "|" + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_TEXT + to_lower_keys = FALSE + +/datum/config_entry/keyed_list/connection_relay_con + splitter = "|" + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_TEXT + to_lower_keys = FALSE diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index 8bff79fa14f6..6e5aa967e907 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -13,6 +13,25 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) /datum/ping_relay_tgui/ui_state(mob/user) return GLOB.always_state +/datum/ping_relay_tgui/ui_static_data(mob/user) + var/list/data = list() + var/list/relay_names = list() + var/list/relay_pings = list() + var/list/relay_cons = list() + + var/list/relay_ping_conf = CONFIG_GET(keyed_list/connection_relay_ping) + var/list/relay_con_conf = CONFIG_GET(keyed_list/connection_relay_con) + for(var/key in relay_ping_conf) + // assumption: keys are the same in both configs + relay_names += key + relay_pings += relay_ping_conf[key] + relay_cons += relay_con_conf[key] + + data["relay_names"] = relay_names + data["relay_pings"] = relay_pings + data["relay_cons"] = relay_cons + return data + /datum/ping_relay_tgui/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) diff --git a/config/example/config.txt b/config/example/config.txt index f9e0956593a9..f055a5d65bff 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -4,6 +4,7 @@ # $include dbconfig.txt # $include resources.txt # $include icon_source.txt +# $include relays.txt ## Server name: This appears at the top of the screen in-game. In this case it will read "tgstation: station_name" where station_name is the randomly generated name of the station for the round. Remove the # infront of SERVERNAME and replace 'tgstation' with the name of your choice # SERVERNAME spacestation13 diff --git a/config/example/relays.txt b/config/example/relays.txt new file mode 100644 index 000000000000..562e917fa484 --- /dev/null +++ b/config/example/relays.txt @@ -0,0 +1,22 @@ +## Settings controlling the relay ping browser accessed via PingIndicator in TGChat +## Pings are performed by timing how long it takes to download favicon.ico from the PingURL + +## Connection Relays: Name must match both ping and connect pairs +## CONNECTION_RELAY_PING Name|PingURL +## CONNECTION_RELAY_CON Name|ConnectURL +CONNECTION_RELAY_PING Direct|play.cm-ss13.com:8998 +CONNECTION_RELAY_CON Direct|play.cm-ss13.com:1400 +CONNECTION_RELAY_PING United Kingdom, London|uk.cm-ss13.com:8998 +CONNECTION_RELAY_CON United Kingdom, London|uk.cm-ss13.com:1400 +CONNECTION_RELAY_PING France, Gravelines|eu-w.cm-ss13.com:8998 +CONNECTION_RELAY_CON France, Gravelines|eu-w.cm-ss13.com:1400 +CONNECTION_RELAY_PING Poland, Warsaw|eu-e.cm-ss13.com:8998 +CONNECTION_RELAY_CON Poland, Warsaw|eu-e.cm-ss13.com:1400 +CONNECTION_RELAY_PING Oregon, Hillsboro|us-w.cm-ss13.com:8998 +CONNECTION_RELAY_CON Oregon, Hillsboro|us-w.cm-ss13.com:1400 +CONNECTION_RELAY_PING Virginia, Vint Hill|us-e.cm-ss13.com:8998 +CONNECTION_RELAY_CON Virginia, Vint Hill|us-e.cm-ss13.com:1400 +CONNECTION_RELAY_PING Singapore|asia-se.cm-ss13.com:8998 +CONNECTION_RELAY_CON Singapore|asia-se.cm-ss13.com:1400 +CONNECTION_RELAY_PING Australia, Sydney|aus.cm-ss13.com:8998 +CONNECTION_RELAY_CON Australia, Sydney|aus.cm-ss13.com:1400 diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 48f672ee77c1..5b2c316b300d 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -6,7 +6,6 @@ import { Color } from 'common/color'; import { Ping } from 'common/ping'; import { Component } from 'react'; -const RELAY_COUNT = 8; const RED = new Color(220, 40, 40); export class PingResult { @@ -30,16 +29,12 @@ class PingApp extends Component { super(); this.pinger = new Ping(); + this.results = new Array(); this.state = { currentIndex: 0, lastClickedIndex: 0, lastClickedState: false, }; - - this.results = new Array(RELAY_COUNT); - for (let i = 0; i < RELAY_COUNT; i++) { - this.results[i] = new PingResult(); - } } startTest(desc, pingURL, connectURL) { @@ -64,42 +59,15 @@ class PingApp extends Component { } componentDidMount() { - this.startTest('Direct', 'play.cm-ss13.com:8998', 'play.cm-ss13.com:1400'); - this.startTest( - 'United Kingdom, London', - 'uk.cm-ss13.com:8998', - 'uk.cm-ss13.com:1400' - ); - this.startTest( - 'France, Gravelines', - 'eu-w.cm-ss13.com:8998', - 'eu-w.cm-ss13.com:1400' - ); - this.startTest( - 'Poland, Warsaw', - 'eu-e.cm-ss13.com:8998', - 'eu-e.cm-ss13.com:1400' - ); - this.startTest( - 'Oregon, Hillsboro', - 'us-w.cm-ss13.com:8998', - 'us-w.cm-ss13.com:1400' - ); - this.startTest( - 'Virginia, Vint Hill', - 'us-e.cm-ss13.com:8998', - 'us-e.cm-ss13.com:1400' - ); - this.startTest( - 'Singapore', - 'asia-se.cm-ss13.com:8998', - 'asia-se.cm-ss13.com:1400' - ); - this.startTest( - 'Australia, Sydney', - 'aus.cm-ss13.com:8998', - 'aus.cm-ss13.com:1400' - ); + this.setState({ currentIndex: 0 }); + for (let i = 0; i < this.props.relayNames.length; i++) { + this.results.push(new PingResult()); + this.startTest( + this.props.relayNames[i], + this.props.relayPings[i], + this.props.relayCons[i] + ); + } } componentWillUnmount() { @@ -188,10 +156,17 @@ class PingApp extends Component { } export const PingRelaysPanel = () => { + const { data } = useBackend(); + const { relay_names, relay_pings, relay_cons } = data; + return ( - + ); From d33cf14cdffee6e48ddd762e2ffe01d4b3bda0f7 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 22 Feb 2024 15:25:38 -0800 Subject: [PATCH 16/18] Disable UI if nothing is configured --- code/modules/tgui_panel/ping_relay.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index 6e5aa967e907..6c0508bd99e7 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -4,6 +4,11 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) GLOB.relays_panel.tgui_interact(client.mob) /datum/ping_relay_tgui/tgui_interact(mob/user, datum/tgui/ui) + var/list/relay_ping_conf = CONFIG_GET(keyed_list/connection_relay_ping) + if(!length(relay_ping_conf)) + to_chat(user, "There are no relays configured to test.") + return + ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "PingRelaysPanel", "Relay Pings") From 336ae657fc9ac9da61c630eba8e321d34a016d81 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 22 Feb 2024 15:34:52 -0800 Subject: [PATCH 17/18] Refactor to_lower_keys to a different key_mode --- code/controllers/configuration/config_entry.dm | 6 +++--- code/controllers/configuration/entries/general.dm | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index 2cc5107fdbc8..d71bf1d747c9 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -4,6 +4,7 @@ #define KEY_MODE_TEXT 0 #define KEY_MODE_TYPE 1 +#define KEY_MODE_TEXT_UNALTERED 2 /datum/config_entry var/name //read-only, this is determined by the last portion of the derived entry type @@ -137,7 +138,6 @@ var/key_mode var/value_mode var/splitter = " " - var/to_lower_keys = TRUE /datum/config_entry/keyed_list/New() . = ..() @@ -155,7 +155,7 @@ if(key_pos || value_mode == VALUE_MODE_FLAG) key_name = copytext(str_val, 1, key_pos) - if(to_lower_keys) + if(key_mode != KEY_MODE_TEXT_UNALTERED) key_name = lowertext(key_name) if(key_pos) key_value = copytext(str_val, key_pos + length(str_val[key_pos])) @@ -164,7 +164,7 @@ var/continue_check_value var/continue_check_key switch(key_mode) - if(KEY_MODE_TEXT) + if(KEY_MODE_TEXT, KEY_MODE_TEXT_UNALTERED) new_key = key_name continue_check_key = new_key if(KEY_MODE_TYPE) diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 1a374f7180f3..e2572e5e2d61 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -633,12 +633,10 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /// Relay Ping Browser configuration /datum/config_entry/keyed_list/connection_relay_ping splitter = "|" - key_mode = KEY_MODE_TEXT + key_mode = KEY_MODE_TEXT_UNALTERED value_mode = VALUE_MODE_TEXT - to_lower_keys = FALSE /datum/config_entry/keyed_list/connection_relay_con splitter = "|" - key_mode = KEY_MODE_TEXT + key_mode = KEY_MODE_TEXT_UNALTERED value_mode = VALUE_MODE_TEXT - to_lower_keys = FALSE From 08f7f76c18e83585fe3f642e38a68b21aaa34345 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Fri, 23 Feb 2024 09:01:17 -0800 Subject: [PATCH 18/18] Add to_chat message when connecting. --- code/modules/tgui_panel/ping_relay.dm | 1 + tgui/packages/tgui/interfaces/PingRelaysPanel.jsx | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/tgui_panel/ping_relay.dm b/code/modules/tgui_panel/ping_relay.dm index 6c0508bd99e7..36929a2e33b0 100644 --- a/code/modules/tgui_panel/ping_relay.dm +++ b/code/modules/tgui_panel/ping_relay.dm @@ -46,6 +46,7 @@ GLOBAL_DATUM_INIT(relays_panel, /datum/ping_relay_tgui, new) switch(action) if("connect") + to_chat(user, "Now connecting via [params["desc"]]. Please wait..."); user << link(params["url"]) ui.close() return diff --git a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx index 5b2c316b300d..7b6c3016504e 100644 --- a/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx +++ b/tgui/packages/tgui/interfaces/PingRelaysPanel.jsx @@ -90,7 +90,9 @@ class PingApp extends Component { onConfirmChange={(clickedOnce) => this.handleConfirmChange(i, clickedOnce) } - onClick={() => act('connect', { url: result.url })}> + onClick={() => + act('connect', { url: result.url, desc: result.desc }) + }> {result.ping <= -1 && result.error === null && (