diff --git a/api/db.js b/api/db.js index e89025f..7c235b2 100644 --- a/api/db.js +++ b/api/db.js @@ -317,6 +317,17 @@ export async function get_account_by_name(name) { } } +export async function get_character_by_name(name) { + try { + const account = await pool.query('SELECT id, account_id, name, faction_id, created, last_login FROM characters WHERE name=$1 AND deleted=false', [name]); + return account.rows[0]; + } catch (e) { + if (e.code) + e.code = pg_error_inv[e.code] + throw e; + } +} + export async function create_account(username, password) { try { const passhash = await bcrypt.hash(password, BCRYPT_ROUNDS); diff --git a/api/info.js b/api/info.js index 55e44ea..62e1864 100644 --- a/api/info.js +++ b/api/info.js @@ -1,12 +1,25 @@ import express from 'express' import * as db from './db.js' +import {get_server_info} from './psadmin.js' const api = express.Router(); api.get('/stats', async (req, res, next) => { try { const stats = await db.get_stats(); - res.status(200).json({ ...stats }); + const info = get_server_info(); + let player_info = [] + let players = info.players; + for (let i = 0; i < players.length; i++) { + const char = await db.get_character_by_name(players[i]); + + if (char) + player_info = player_info.concat(char) + else + console.log("WARNING: cannot find player info " + players[i]) + } + info.players = player_info + res.status(200).json({ ...stats, ...info }); } catch (e) { console.log(e); res.status(500).json({ message : 'error' }); diff --git a/api/psadmin.js b/api/psadmin.js new file mode 100644 index 0000000..a1f1183 --- /dev/null +++ b/api/psadmin.js @@ -0,0 +1,83 @@ +import net from 'net' + +let error_count = 0; +let server_info = {} + +let psadmin_port = 0; +let psadmin_domain = ""; + +export async function start_server_polling() { + const connect_to = process.env.PSADMIN; + + if (!connect_to) { + console.log("WARNING: PSADMIN not configured. Not polling server") + return + } else { + const tokens = connect_to.split(":") + + psadmin_domain = tokens[0] + psadmin_port = tokens[1] + console.log("Starting PSAdmin polling for " + connect_to) + } + + if (!(await poll_server())) { + console.log("WARNING: initial PSAdmin poll FAILED! Are you sure the server is up and the config is right?") + } + + setInterval(poll_server, 10000) +} + +async function poll_server() { + try { + const player_list = await get_player_list(); + server_info = {status : "UP",players : player_list} + + if (error_count > 0) { + console.log("PSAdmin connection has returned after " + error_count + " errors") + } + + error_count = 0; + + return true; + } catch (e) { + if (error_count < 5) + console.log("WARNING: Failed to get player list: " + e) + + server_info = {status : "DOWN",players : []} + error_count += 1 + return false; + } +} + +export function get_server_info() { + return server_info; +} + +async function get_player_list() { + return new Promise((resolve, reject) => { + const client = new net.Socket(); + + client.connect(psadmin_port, psadmin_domain, function() { + client.write('list_players\n'); + }); + + client.on('error', function(e) { + reject(e) + client.destroy() + }); + + client.on('data', function(data) { + try { + const info = JSON.parse(data); + resolve(info.player_list) + } catch (e) { + reject(new Error("Failed to parse PSFCI JSON response")) + } finally { + client.destroy(); // kill client after server's response + } + }); + + client.on('close', function() { + }); + }); +} diff --git a/app/views/Home.svelte b/app/views/Home.svelte index ab7dfcd..24f961b 100644 --- a/app/views/Home.svelte +++ b/app/views/Home.svelte @@ -13,6 +13,7 @@ let stats; let alert; + let players; function format_account(account) { return `${account.username}` @@ -22,6 +23,7 @@ try { const resp = await axios.get("/api/stats") stats = resp.data; + players = stats.players alert.message("") } catch (e) { console.log(e) @@ -40,27 +42,44 @@ {#if stats}
- Server address: play.psforever.net:51200 (Setup Instructions)
- PSForever accounts: {stats.accounts.toLocaleString()}
- Server characters: {stats.characters.toLocaleString()}
- Last character created:
play.psforever.net:51000
+