Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relay Ping Browser #5777

Merged
merged 18 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions code/controllers/configuration/config_entry.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -153,15 +154,17 @@
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(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]))
var/new_key
var/new_value
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)
Expand Down
11 changes: 11 additions & 0 deletions code/controllers/configuration/entries/general.dm
Original file line number Diff line number Diff line change
Expand Up @@ -629,3 +629,14 @@ 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_UNALTERED
value_mode = VALUE_MODE_TEXT

/datum/config_entry/keyed_list/connection_relay_con
splitter = "|"
key_mode = KEY_MODE_TEXT_UNALTERED
value_mode = VALUE_MODE_TEXT
52 changes: 52 additions & 0 deletions code/modules/tgui_panel/ping_relay.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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)
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")
ui.open()
ui.set_autoupdate(FALSE)

/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(.)
return

var/mob/user = ui.user

switch(action)
if("connect")
to_chat(user, "Now connecting via [params["desc"]]. Please wait...");
user << link(params["url"])
ui.close()
return
3 changes: 3 additions & 0 deletions code/modules/tgui_panel/tgui_panel.dm
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
if(type == "telemetry")
analyze_telemetry(payload)
return TRUE
if(type == "act/ping_relays")
ping_relays()
return TRUE

/**
* public
Expand Down
1 change: 1 addition & 0 deletions colonialmarines.dme
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions config/example/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions config/example/relays.txt
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions tgui/docs/component-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
108 changes: 108 additions & 0 deletions tgui/packages/common/ping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Adapted pinging library based on:
* @file https://www.jsdelivr.com/package/npm/ping.js
* @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 || 10000;
this.logError = this.opt.logError || false;
this.abort = 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 = 1000) {
this.abort = false;
let timer;
if (delay > 0) {
timer = setTimeout(() => {
if (this.abort) {
return;
}
this.pingNow(source, callback);
}, delay);
return;
}
this.pingNow(source, callback);
}

/**
* 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.
*/
pingNow(source, callback) {
let self = this;
self.abort = false;
self.wasSuccess = false;
self.img = new Image();
self.img.onload = (e) => {
self.wasSuccess = true;
pingCheck.call(self, e);
};
self.img.onerror = (e) => {
self.wasSuccess = false;
pingCheck.call(self, e);
};

let timer;
let start = new Date();

if (self.timeout) {
timer = setTimeout(() => {
self.wasSuccess = false;
pingCheck.call(self, undefined);
}, self.timeout);
}

/**
* Times ping and triggers callback.
*/
const pingCheck = function (e) {
if (timer) {
clearTimeout(timer);
}
if (this.abort) {
return;
}
let pong = new Date() - start;

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: ' + e.error);
}
return callback(e ? 'Error' : 'Timed Out', 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
}

/**
* Aborts any pending ping request.
*/
cancel() {
this.abort = true;
}
}
19 changes: 15 additions & 4 deletions tgui/packages/tgui-panel/ping/PingIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -19,9 +20,19 @@ export const PingIndicator = (props) => {
]);
const roundtrip = ping.roundtrip ? toFixed(ping.roundtrip) : '--';
return (
<div className="Ping">
<Button
lineHeight="15px"
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')}>
<Box className="Ping__indicator" backgroundColor={color} />
Drulikar marked this conversation as resolved.
Show resolved Hide resolved
Drulikar marked this conversation as resolved.
Show resolved Hide resolved
{roundtrip}
</div>
</Button>
);
};
4 changes: 4 additions & 0 deletions tgui/packages/tgui/components/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ export class ButtonConfirm extends Component {
} else {
window.removeEventListener('click', this.handleClick);
}
if (this.props.onConfirmChange) {
this.props.onConfirmChange(clickedOnce);
}
}

render() {
Expand All @@ -183,6 +186,7 @@ export class ButtonConfirm extends Component {
color,
content,
onClick,
onConfirmChange,
...rest
} = this.props;
return (
Expand Down
Loading
Loading