feat: add support for source 2

This commit is contained in:
2023-10-22 19:33:42 +02:00
parent 24e44a346d
commit 14ace4cd49
6 changed files with 106 additions and 59 deletions

View File

@@ -1,6 +1,6 @@
import express from 'express';
import { connect } from 'working-rcon';
import module from './modules/index.js';
import SourceRcon from '@hellz.fr/sourcecon';
const app = express();
@@ -30,16 +30,17 @@ app.get('/metrics', async (req, res) => {
return;
}
if (!['csgo', 'cstrike', 'gmod'].includes(config.game)) {
if (!['csgo', 'cstrike', 'gmod', 'cs2'].includes(config.game)) {
res.send('Incorrect game value, currently supported games are : csgo, gmod, cstrike');
return;
}
try {
const client = await connect(config.ip, config.port, config.rconPassword, 5000);
const client = new SourceRcon.default(config.ip, Number.parseInt(config.port));
await client.connect();
await client.auth(config.rconPassword);
const response = await module.request(config, client);
await module.send(config, response, res);
await client.disconnect();
} catch (e) {
if (e.code === 'EHOSTUNREACH') {
console.error(`Unreachable host : ${e.address}:${e.port}`);

View File

@@ -6,6 +6,8 @@ export default {
const stats = await utils.rconCommand(client, 'status');
let statusLine = null;
let res = null;
let tv = null;
let regexStatus = null;
if (stats) {
statusLine = stats.split(/\r?\n/);
} else {
@@ -17,32 +19,70 @@ export default {
statusLine.shift();
statusLine.shift();
statusLine.shift();
if (game === 'csgo') {
if (statusLine[0].search('gotv') !== -1) {
statusLine.shift();
}
res = statusLine[0].split(/players : (\d+) humans, (\d+) bots \((\d+)\/0 max\)/);
} else {
if (statusLine[0].search('sourcetv') !== -1) {
statusLine.shift();
}
res = statusLine[0].split(/players : (\d+) humans, (\d+) bots \((\d+) max\)/);
}
res.pop();
res.shift();
if (game === "csgo") {
tv = "gotv";
regexStatus = /players : (\d+) humans, (\d+) bots \((\d+)\/0 max\)/;
} else {
tv = "sourcetv";
regexStatus = /players : (\d+) humans, (\d+) bots \((\d+) max\)/;
}
if (statusLine[0].search(tv) !== -1) {
statusLine.shift();
}
res = statusLine[0].split(regexStatus);
res.pop();
res.shift();
return res;
},
setStatusMetrics(response) {
let players = 0;
let bots = 0;
let maxPlayers = 0;
if (response) {
[players, bots, maxPlayers] = response;
}
metrics.players.set((Number(players)));
metrics.bots.set((Number(bots)));
metrics.maxPlayers.set((Number(maxPlayers)));
},
async requestStatusCs2(client, game) {
let stats = await utils.rconCommand(client, 'status_json');
stats = JSON.parse(stats)
return stats;
},
setStatusMetrics(response) {
let players = 0;
let bots = 0;
let maxPlayers = 0;
if (response) {
[players, bots, maxPlayers] = response;
}
metrics.players.set((Number(players)));
metrics.bots.set((Number(bots)));
metrics.maxPlayers.set((Number(maxPlayers)));
},
setCs2StatusMetrics(response) {
let clients_human = 0;
let clients_bot = 0;
let cpu = 0;
let status = 0;
let uptime = 0;
let maps = '';
if (response) {
let { server } = response;
uptime = response.process_uptime
clients_human = server.clients_human;
clients_bot = server.clients_bot;
cpu = server.cpu_usage;
maps = server.maps;
status = 1;
}
metrics.players.set((Number(clients_human)));
metrics.bots.set((Number(clients_bot)));
//metrics.maxPlayers.set((Number(maxPlayers)));
metrics.status.set((Number(status)));
metrics.cpu.set((Number(cpu)));
//metrics.netin.set((Number(netin)));
//metrics.netout.set((Number(netout)));
metrics.uptime.set((Number(uptime)));
//metrics.maps.set((Number(maps)));
// metrics.fps.set((Number(fps)));
// metrics.svms.set((Number(svms)));
// metrics.varms.set((Number(varms)));
//metrics.svMaxUpdateRate.set((Number(maxUpdateRate)));
},
async requestStats(client, game) {
const stats = await utils.rconCommand(client, 'stats');
let statusLine = null;

View File

@@ -35,10 +35,17 @@ export default {
let metamodResponse;
let sourcemodResponse;
let sourcepythonResponse;
let infoResponse;
let statsResponse;
let statusResponse;
const infoResponse = await game.requeseInfo(client, config.game);
const statsResponse = await game.requestStats(client, config.game);
const statusResponse = await game.requestStatus(client, config.game);
if (config.game === 'cs2') {
statusResponse = await game.requestStatusCs2(client, config.game);
} else {
infoResponse = await game.requeseInfo(client, config.game);
statsResponse = await game.requestStats(client, config.game);
statusResponse = await game.requestStatus(client, config.game);
}
if (config.metamod) {
metamodResponse = await metamod.request(client);
}
@@ -64,10 +71,12 @@ export default {
sourcemod.setMetrics(response ? response.sourcemod : null);
sourcepython.setMetrics(response ? response.sourcepython : null);
gametracker.setMetrics(response ? response.gametracker : null);
game.setStatsMetrics(response ? response.stats : null, config.game);
game.setInfoMetrics(response ? response.info : null);
game.setStatusMetrics(response ? response.status : null);
if (config.game !== 'cs2') {
game.setStatsMetrics(response ? response.stats : null, config.game);
game.setInfoMetrics(response ? response.info : null);
} else {
game.setCs2StatusMetrics(response ? response.status : null);
}
registry.setDefaultLabels(
config.ip,
config.port,
@@ -77,7 +86,6 @@ export default {
response ? response.sourcemod : null,
response ? response.sourcepython : null,
);
registry.sendMetrics(config.game, res);
},
};

View File

@@ -4,16 +4,19 @@ import utils from '../utils/utils.js';
const csgoRegistry = new prometheus.Registry();
const gmodRegistry = new prometheus.Registry();
const cstrikeRegistry = new prometheus.Registry();
const cs2Registry = new prometheus.Registry();
const allGameMetrics = [
csgoRegistry,
gmodRegistry,
cstrikeRegistry,
cs2Registry,
];
export default {
csgoRegistry,
gmodRegistry,
cstrikeRegistry,
cs2Registry,
allGameMetrics,
setDefaultLabels(ip, port, game, tags, metamodResponse, sourcemodResponse, sourcepythonResponse) {
@@ -36,9 +39,11 @@ export default {
const version = line.replace('SP version : ', '').trim();
defaultLabels.sourcepython = version;
}
if (game === 'csgo') {
csgoRegistry.setDefaultLabels(defaultLabels);
} else if (game === 'cstrike') {
if (game === 'cs2') {
cs2Registry.setDefaultLabels(defaultLabels);
} else if (game === 'csgo') {
csgoRegistry.setDefaultLabels(defaultLabels);
} else if (game === 'cstrike') {
cstrikeRegistry.setDefaultLabels(defaultLabels);
} else if (game === 'gmod') {
gmodRegistry.setDefaultLabels(defaultLabels);
@@ -46,9 +51,11 @@ export default {
},
sendMetrics(game, res) {
if (game === 'csgo') {
res.end(csgoRegistry.metrics());
} else if (game === 'cstrike') {
if (game === 'cs2') {
res.end(cs2Registry.metrics());
} else if (game === 'csgo') {
res.end(csgoRegistry.metrics());
} else if (game === 'cstrike') {
res.end(cstrikeRegistry.metrics());
} else if (game === 'gmod') {
res.end(gmodRegistry.metrics());

View File

@@ -11,28 +11,24 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/Unyxos/srcds-exporter.git"
"url": "git+https://github.com/Sithranduil/srcds-exporter.git"
},
"author": "Corentin Closs <me@corentincloss.fr>",
"author": "Corentin Closs <me@corentincloss.fr>, Sithranduil",
"license": "ISC",
"bugs": {
"url": "https://github.com/Unyxos/srcds-exporter/issues"
"url": "https://github.com/Sithranduil/srcds-exporter/issues"
},
"homepage": "https://github.com/Unyxos/srcds-exporter#readme",
"homepage": "https://github.com/Sithranduil/srcds-exporter#readme",
"dependencies": {
"@hellz.fr/sourcecon": "^1.0.0",
"express": "^4.17.1",
"got": "^11.8.0",
"jsdom": "^16.4.0",
"prom-client": "^11.5.3",
"srcds-rcon": "^2.2.1",
"working-rcon": "^0.2.8"
"prom-client": "^11.5.3"
},
"devDependencies": {
"eslint": "^7.2.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.21.3",
"eslint-plugin-react-hooks": "^4.0.0"
"eslint-plugin-import": "^2.22.1"
}
}

View File

@@ -1,4 +1,3 @@
import { TimeoutError } from 'working-rcon';
import got from 'got';
import jsdom from 'jsdom';
@@ -22,13 +21,9 @@ export default {
},
async rconCommand(client, command) {
try {
return client.command(command);
return client.send(command);
} catch (err) {
if (err instanceof TimeoutError) {
console.error('request timed out');
} else {
throw err;
}
}
return null;
},