discord bot, index redirect, refactoring

This commit is contained in:
Smith
2022-04-05 17:12:43 +02:00
parent fb749b5515
commit 37666a8977
13 changed files with 494 additions and 318 deletions

View File

@@ -1,7 +1,8 @@
<html>
<head>
<meta http-equiv="refresh" content="7; url='https://github.com/a-sync/game-server-watcher'" />
</head>
<body>
gsw...index
<p>Please follow <a href="https://github.com/a-sync/game-server-watcher">this link</a>.</p>
</body>
</html>
</html>

View File

@@ -11,8 +11,8 @@ const watcher_1 = require("./src/watcher");
const CACHE_MAX_AGE = parseInt(process.env.CACHE_MAX_AGE || '0', 10);
const APP_HOST = process.env.app_host || '0.0.0.0';
const APP_PORT = parseInt(process.env.app_port || '8080', 10);
const DBG = Boolean(process.env.DBG || false);
const SECRET = process.env.SECRET || 'secret';
const DBG = Boolean(process.env.DBG || false);
(0, http_1.createServer)(async (req, res) => {
if (DBG)
console.log('DBG: %j %j', (new Date()), req.url);
@@ -24,17 +24,6 @@ const SECRET = process.env.SECRET || 'secret';
});
fs_1.default.createReadStream('./index.html').pipe(res);
}
else if (reqUrl.pathname === '/discord/post') { //DEBUG
console.log('REQ.HEADERS', req.headers);
let body = '';
req.on('data', (chunk) => {
body += chunk; // convert Buffer to string
});
req.on('end', () => {
console.log('POST.DATA:', String(body));
res.end('');
});
}
else if (reqUrl.pathname === '/ping') {
console.log('ping');
res.end('pong');

View File

@@ -4,14 +4,13 @@ import { URL } from 'url';
import 'dotenv/config';
import { main, WatcherConfig } from './src/watcher';
import { main } from './src/watcher';
const CACHE_MAX_AGE = parseInt(process.env.CACHE_MAX_AGE || '0', 10);
const APP_HOST = process.env.app_host || '0.0.0.0';
const APP_PORT = parseInt(process.env.app_port || '8080', 10);
const DBG = Boolean(process.env.DBG || false);
const SECRET = process.env.SECRET || 'secret';
const DBG = Boolean(process.env.DBG || false);
createServer(async (req, res) => {
if (DBG) console.log('DBG: %j %j', (new Date()), req.url);
@@ -24,17 +23,6 @@ createServer(async (req, res) => {
});
fs.createReadStream('./index.html').pipe(res);
}
else if (reqUrl.pathname === '/discord/post') {//DEBUG
console.log('REQ.HEADERS', req.headers);
let body = '';
req.on('data', (chunk) => {
body += chunk; // convert Buffer to string
});
req.on('end', () => {
console.log('POST.DATA:', String(body));
res.end('');
});
}
else if (reqUrl.pathname === '/ping') {
console.log('ping');
res.end('pong');

View File

@@ -1,81 +1,150 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.serverUpdate = exports.init = void 0;
const discord_js_1 = require("discord.js");
//https://github.com/soulkobk/DiscordBot_GameStatus
const prefix = '@gsw';
let client;
function init(token) {
client = new discord_js_1.Client({
//messageEditHistoryMaxSize: 0,
//ws: {intents: ['GUILDS', 'GUILD_MESSAGES']}
const lowdb_1 = require("@commonify/lowdb");
const hhmmss_1 = __importDefault(require("./lib/hhmmss"));
const DATA_PATH = process.env.DATA_PATH || './data/';
const DBG = Boolean(process.env.DBG || false);
const adapter = new lowdb_1.JSONFile(DATA_PATH + 'discord.json');
const db = new lowdb_1.Low(adapter);
const serverInfoMessages = [];
let bot;
async function init(token) {
console.log('discord-bot starting...');
bot = new discord_js_1.Client({
messageEditHistoryMaxSize: 0,
ws: { intents: ['GUILDS', 'GUILD_MESSAGES'] }
});
console.log(' dc.init'); //DEBUG
client.on('ready', () => {
console.log(' dc.client.READY'); //DEBUG
bot.on('error', e => {
console.error('discord-bot ERROR', e.message || e);
});
client.on('message', msg => {
if (msg.content === 'ping') {
msg.reply('pong');
await new Promise((resolve, reject) => {
bot.once('ready', () => {
console.log('discord-bot ready', bot.user);
bot.removeListener('error', reject);
resolve();
});
bot.once('error', reject);
if (DBG) {
bot.on('message', msg => {
if (msg.content === 'ping') {
msg.reply('pong');
}
});
}
return bot.login(token);
});
// client.on('messageCreate', (message) => {
// console.log('!!!!!dc.messageCreate', message.author, message.content);//DEBUG
// if (message.author.bot) return;
// if (!message.content.startsWith(prefix)) return;
// const commandBody = message.content.slice(prefix.length);
// const args = commandBody.split(' ');
// const command = String(args.shift()).toLowerCase();
// if (command === 'ping') {
// const timeTaken = Date.now() - message.createdTimestamp;
// message.reply(`Pong! ${timeTaken}ms`);
// }
// });
return client.login(token);
await db.read();
db.data = db.data || [];
}
exports.init = init;
async function serverUpdate(gs) {
if (!gs.info)
return;
console.log('discord.serverUpdate', gs.config.host, gs.config.port, gs.config.discord);
/*
for (const cid of gs.config.discord.chatIds) {
let m = await getServerInfoMessage(cid, gs.config.host, gs.config.port);
const stats = gs.history.stats();
let statsText = '';
if (stats.length > 0) {
const s = stats.pop();
if (s) {
statsText = ' (hourly max: ' + s.max + ', hourly avg: ' + s.avg.toFixed(1) + ')';
}
}
const infoText: string[] = [
gs.niceName,
gs.info.game + ' / ' + gs.info.map,
gs.info.connect,
'Players ' + gs.info.playersNum + '/' + gs.info.playersMax + statsText
];
if (gs.info?.players.length > 0) {
infoText.push('```');
for(const p of gs.info?.players) {
let playerLine = '';
if (p.raw?.time !== undefined) {
playerLine += '[' + hhmmss(p.raw.time) + '] ';
}
playerLine += p.name;
if (p.raw?.score !== undefined) {
playerLine += ' [score: ' + p.raw.score + ']';
}
infoText.push(playerLine);
}
infoText.push('```');
}
m.setText(infoText.join('\n'));
}
*/
if (DBG)
console.log('discord.serverUpdate', gs.config.host, gs.config.port, gs.config.discord);
for (const cid of gs.config.discord.channelIds) {
let m = await getServerInfoMessage(cid, gs.config.host, gs.config.port);
m.updatePost(gs);
}
}
exports.serverUpdate = serverUpdate;
async function getServerInfoMessage(cid, host, port) {
let m = serverInfoMessages.find(n => {
return n.channelId === cid && n.host === host && n.port === port;
});
if (!m) {
m = new ServerInfoMessage(cid, host, port);
let msgId;
if (db.data) {
const md = db.data.find(d => {
return d.channelId === cid && d.host === host && d.port === port;
});
if (md) {
msgId = md.messageId;
}
}
await m.init(msgId);
serverInfoMessages.push(m);
}
return m;
}
class ServerInfoMessage {
constructor(channelId, host, port) {
this.messageId = '0';
this.channelId = channelId;
this.host = host;
this.port = port;
}
async init(msgId) {
this.channel = await bot.channels.fetch(this.channelId);
if (msgId) {
this.messageId = msgId;
this.message = await this.channel.messages.fetch(msgId);
}
else {
let embed = new discord_js_1.MessageEmbed();
embed.setTitle('Initializing server info... ' + (new Date()).toISOString());
embed.setColor('#00ff00');
this.message = await this.channel.send({ embed });
this.messageId = this.message.id;
}
if (db.data) {
const mi = db.data.findIndex(d => {
return d.channelId === this.channelId && d.host === this.host && d.port === this.port;
});
if (mi === -1 || mi === undefined) {
db.data.push({
channelId: this.channelId,
host: this.host,
port: this.port,
messageId: this.messageId
});
}
else {
db.data[mi].messageId = this.messageId;
}
await db.write();
}
}
async updatePost(gs) {
var _a, _b, _c, _d;
if (!this.message)
return;
const embed = new discord_js_1.MessageEmbed();
embed.setTitle(gs.niceName + ' offline...');
embed.setColor('#ff0000');
embed.setFooter('Last updated');
embed.setTimestamp();
if (gs.info && gs.online) {
embed.setTitle(gs.niceName);
embed.setColor('#000000');
embed.addField('Game', gs.info.game, true);
embed.addField('Map', gs.info.map, true);
embed.addField('Connect', 'steam://connect/' + gs.info.connect);
if (((_a = gs.info) === null || _a === void 0 ? void 0 : _a.players.length) > 0) {
const pNames = [];
const pTimes = [];
const pScores = [];
let c = 0;
for (const p of (_b = gs.info) === null || _b === void 0 ? void 0 : _b.players) {
c++;
pNames.push(p.name || 'n/a');
pTimes.push((0, hhmmss_1.default)(((_c = p.raw) === null || _c === void 0 ? void 0 : _c.time) || 0));
pScores.push(((_d = p.raw) === null || _d === void 0 ? void 0 : _d.score) || '0');
}
embed.addField('Players ' + gs.info.playersNum + '/' + gs.info.playersMax, '```\n' + pNames.join('\n').slice(0, 1016) + '\n```', true);
embed.addField('Time', '```\n' + pTimes.join('\n').slice(0, 1016) + '\n```', true);
embed.addField('Score', '```\n' + pScores.join('\n').slice(0, 1016) + '\n```', true);
}
}
try {
await this.message.edit(null, { embed });
}
catch (e) {
console.log(e.message || e);
}
}
}

View File

@@ -1,89 +1,183 @@
import {Client, MessageEmbed, Intents} from 'discord.js';
import { Client, MessageEmbed, TextChannel, Message } from 'discord.js';
import { Low, JSONFile } from '@commonify/lowdb';
import { GameServer } from './game-server';
import hhmmss from './lib/hhmmss';
//https://github.com/soulkobk/DiscordBot_GameStatus
const prefix = '@gsw';
let client: Client;
const DATA_PATH = process.env.DATA_PATH || './data/';
const DBG = Boolean(process.env.DBG || false);
export function init(token: string) {
client = new Client({
//messageEditHistoryMaxSize: 0,
//ws: {intents: ['GUILDS', 'GUILD_MESSAGES']}
interface DiscordData {
channelId: string;
host: string;
port: number;
messageId: string;
}
const adapter = new JSONFile<DiscordData[]>(DATA_PATH + 'discord.json');
const db = new Low<DiscordData[]>(adapter);
const serverInfoMessages: ServerInfoMessage[] = [];
let bot: Client;
export async function init(token: string) {
console.log('discord-bot starting...');
bot = new Client({
messageEditHistoryMaxSize: 0,
ws: { intents: ['GUILDS', 'GUILD_MESSAGES'] }
});
console.log(' dc.init');//DEBUG
bot.on('error', e => {
console.error('discord-bot ERROR', e.message || e);
});
client.on('ready', ()=> {
console.log(' dc.client.READY');//DEBUG
})
await new Promise<void>((resolve, reject) => {
bot.once('ready', () => {
console.log('discord-bot ready', bot.user);
client.on('message', msg => {
if (msg.content === 'ping') {
msg.reply('pong');
bot.removeListener('error', reject);
resolve();
});
bot.once('error', reject);
if (DBG) {
bot.on('message', msg => {
if (msg.content === 'ping') {
msg.reply('pong');
}
});
}
return bot.login(token);
});
// client.on('messageCreate', (message) => {
// console.log('!!!!!dc.messageCreate', message.author, message.content);//DEBUG
// if (message.author.bot) return;
// if (!message.content.startsWith(prefix)) return;
// const commandBody = message.content.slice(prefix.length);
// const args = commandBody.split(' ');
// const command = String(args.shift()).toLowerCase();
// if (command === 'ping') {
// const timeTaken = Date.now() - message.createdTimestamp;
// message.reply(`Pong! ${timeTaken}ms`);
// }
// });
return client.login(token);
await db.read();
db.data = db.data || [];
}
export async function serverUpdate(gs: GameServer) {
if (!gs.info) return;
if (DBG) console.log('discord.serverUpdate', gs.config.host, gs.config.port, gs.config.discord);
console.log('discord.serverUpdate', gs.config.host, gs.config.port, gs.config.discord);
/*
for (const cid of gs.config.discord.chatIds) {
for (const cid of gs.config.discord.channelIds) {
let m = await getServerInfoMessage(cid, gs.config.host, gs.config.port);
const stats = gs.history.stats();
let statsText = '';
if (stats.length > 0) {
const s = stats.pop();
if (s) {
statsText = ' (hourly max: ' + s.max + ', hourly avg: ' + s.avg.toFixed(1) + ')';
}
}
const infoText: string[] = [
gs.niceName,
gs.info.game + ' / ' + gs.info.map,
gs.info.connect,
'Players ' + gs.info.playersNum + '/' + gs.info.playersMax + statsText
];
if (gs.info?.players.length > 0) {
infoText.push('```');
for(const p of gs.info?.players) {
let playerLine = '';
if (p.raw?.time !== undefined) {
playerLine += '[' + hhmmss(p.raw.time) + '] ';
}
playerLine += p.name;
if (p.raw?.score !== undefined) {
playerLine += ' [score: ' + p.raw.score + ']';
}
infoText.push(playerLine);
}
infoText.push('```');
}
m.setText(infoText.join('\n'));
m.updatePost(gs);
}
*/
}
}
async function getServerInfoMessage(cid: string, host: string, port: number) {
let m = serverInfoMessages.find(n => {
return n.channelId === cid && n.host === host && n.port === port;
});
if (!m) {
m = new ServerInfoMessage(cid, host, port);
let msgId;
if (db.data) {
const md = db.data.find(d => {
return d.channelId === cid && d.host === host && d.port === port;
});
if (md) {
msgId = md.messageId;
}
}
await m.init(msgId);
serverInfoMessages.push(m);
}
return m;
}
class ServerInfoMessage {
public channelId: string;
public host: string;
public port: number;
public messageId: string = '0';
private channel?: TextChannel;
private message?: Message;
constructor(channelId: string, host: string, port: number) {
this.channelId = channelId;
this.host = host;
this.port = port;
}
async init(msgId?: string) {
this.channel = await bot.channels.fetch(this.channelId) as TextChannel;
if (msgId) {
this.messageId = msgId;
this.message = await this.channel.messages.fetch(msgId);
} else {
let embed = new MessageEmbed();
embed.setTitle('Initializing server info... ' + (new Date()).toISOString());
embed.setColor('#00ff00');
this.message = await this.channel.send({ embed });
this.messageId = this.message.id;
}
if (db.data) {
const mi = db.data.findIndex(d => {
return d.channelId === this.channelId && d.host === this.host && d.port === this.port;
});
if (mi === -1 || mi === undefined) {
db.data.push({
channelId: this.channelId,
host: this.host,
port: this.port,
messageId: this.messageId
});
} else {
db.data[mi].messageId = this.messageId;
}
await db.write();
}
}
async updatePost(gs: GameServer) {
if (!this.message) return;
const embed = new MessageEmbed();
embed.setTitle(gs.niceName + ' offline...');
embed.setColor('#ff0000');
embed.setFooter('Last updated');
embed.setTimestamp();
if (gs.info && gs.online) {
embed.setTitle(gs.niceName);
embed.setColor('#000000');
embed.addField('Game', gs.info.game, true);
embed.addField('Map', gs.info.map, true);
embed.addField('Connect', 'steam://connect/' + gs.info.connect);
if (gs.info?.players.length > 0) {
const pNames: string[] = [];
const pTimes: string[] = [];
const pScores: string[] = [];
let c = 0;
for (const p of gs.info?.players) {
c++;
pNames.push(p.name || 'n/a');
pTimes.push(hhmmss(p.raw?.time || 0));
pScores.push(p.raw?.score || '0');
}
embed.addField('Players ' + gs.info.playersNum + '/' + gs.info.playersMax, '```\n' + pNames.join('\n').slice(0, 1016) + '\n```', true);
embed.addField('Time', '```\n' + pTimes.join('\n').slice(0, 1016) + '\n```', true);
embed.addField('Score', '```\n' + pScores.join('\n').slice(0, 1016) + '\n```', true);
}
}
try {
await this.message.edit(null, { embed });
} catch (e: any) {
console.log(e.message || e);
}
}
}

View File

@@ -27,24 +27,26 @@ function saveDb() {
exports.saveDb = saveDb;
class GameServer {
constructor(config) {
console.log('game-server.init', config.host, config.port, config.type, config.appId);
this.online = false;
console.log('game-server init', config.host, config.port, config.type, config.appId);
this.config = config;
this.history = new ServerHistory(config.host + ':' + config.port);
this._niceName = config.host + ':' + config.port;
}
async update() {
let info;
info = await this.gamedig();
let info = await this.gamedig();
if (!info && STEAM_WEB_API_KEY) {
info = await this.steam();
}
if (info) {
this.online = true;
this.info = info;
this.history.add(info);
}
else {
console.error('game-server.update no info!');
this.online = false;
console.error('game-server not available', this.config.host, this.config.port);
}
return;
}
async gamedig() {
try {
@@ -111,21 +113,25 @@ class GameServer {
}
get niceName() {
var _a;
let nn = ((_a = this.info) === null || _a === void 0 ? void 0 : _a.name) || '';
for (let i = 0; i < nn.length; i++) {
if (nn[i] == '^') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 2);
}
else if (nn[i] == '█') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 1);
}
else if (nn[i] == '<27>') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 2);
let nn = (_a = this.info) === null || _a === void 0 ? void 0 : _a.name;
if (nn) {
for (let i = 0; i < nn.length; i++) {
if (nn[i] == '^') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 2);
}
else if (nn[i] == '█') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 1);
}
else if (nn[i] == '<27>') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 2);
}
;
}
;
if (nn)
this._niceName = nn;
}
;
return nn;
return this._niceName;
}
}
exports.GameServer = GameServer;

View File

@@ -55,29 +55,31 @@ export class GameServer {
public info?: Info;
public config: WatcherConfig;
public history: ServerHistory;
private _niceName: string;
public online: boolean = false;
constructor(config: WatcherConfig) {
console.log('game-server.init', config.host, config.port, config.type, config.appId);
console.log('game-server init', config.host, config.port, config.type, config.appId);
this.config = config;
this.history = new ServerHistory(config.host + ':' + config.port);
this._niceName = config.host + ':' + config.port;
}
async update() {
let info: Info | null;
info = await this.gamedig();
let info = await this.gamedig();
if (!info && STEAM_WEB_API_KEY) {
info = await this.steam();
}
if (info) {
this.online = true;
this.info = info;
this.history.add(info);
} else {
console.error('game-server.update no info!');
this.online = false;
console.error('game-server not available', this.config.host, this.config.port);
}
return;
}
async gamedig(): Promise<Info | null> {
@@ -88,7 +90,7 @@ export class GameServer {
type: this.config.type,
}) as qRes;
const raw = res.raw as { game: string; folder: string;};
const raw = res.raw as { game: string; folder: string; };
const game = raw.game || raw.folder || this.config.type;
const players: Player[] = res.players;//todo: map / filter
@@ -151,19 +153,23 @@ export class GameServer {
}
get niceName() {
let nn = this.info?.name || '';
let nn = this.info?.name;
for (let i = 0; i < nn.length; i++) {
if (nn[i] == '^') {
nn = nn.slice(0, i) + ' ' + nn.slice(i+2);
} else if (nn[i] == '█') {
nn = nn.slice(0, i) + ' ' + nn.slice(i+1);
} else if (nn[i] == '<27>') {
nn = nn.slice(0, i) + ' ' + nn.slice(i+2);
if (nn) {
for (let i = 0; i < nn.length; i++) {
if (nn[i] == '^') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 2);
} else if (nn[i] == '') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 1);
} else if (nn[i] == '<EFBFBD>') {
nn = nn.slice(0, i) + ' ' + nn.slice(i + 2);
};
};
};
return nn;
if (nn) this._niceName = nn;
}
return this._niceName;
}
}
@@ -197,7 +203,7 @@ class ServerHistory {
const d = new Date();
const dh = this.yyyymmddhh(d);
if (!db.data.population[this.id]) {
db.data.population[this.id] = [];
}

View File

@@ -4,12 +4,14 @@ exports.default = (sec_num) => {
let hours = Math.floor(sec_num / 3600);
let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
let secs = Math.floor(sec_num - (hours * 3600) - (minutes * 60));
//if (hours < 10) {hours = `0${hours}`;}
if (hours == 0) {
hours = '';
if (hours === 0) {
hours = '00';
}
else if (hours < 10) {
hours = `0${hours}`;
}
else {
hours = `${hours}:`;
hours = `${hours}`;
}
if (minutes < 10) {
minutes = `0${minutes}`;
@@ -17,5 +19,5 @@ exports.default = (sec_num) => {
if (secs < 10) {
secs = `0${secs}`;
}
return [hours, minutes, ':', secs].join('');
return [hours, ':', minutes, ':', secs].join('');
};

View File

@@ -3,10 +3,10 @@ export default (sec_num: number) => {
let minutes: number | string = Math.floor((sec_num - (hours * 3600)) / 60);
let secs: number | string = Math.floor(sec_num - (hours * 3600) - (minutes * 60));
//if (hours < 10) {hours = `0${hours}`;}
if (hours == 0) {hours = '';}
else {hours = `${hours}:`;}
if (minutes < 10) { minutes = `0${minutes}`; }
if (secs < 10) { secs = `0${secs}`; }
return [hours, minutes, ':', secs].join('');
if (hours === 0) { hours = '00' }
else if (hours < 10) { hours = `0${hours}` }
else { hours = `${hours}` }
if (minutes < 10) { minutes = `0${minutes}` }
if (secs < 10) { secs = `0${secs}` }
return [hours, ':', minutes, ':', secs].join('');
}

View File

@@ -5,9 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.serverUpdate = exports.init = void 0;
const grammy_1 = require("grammy");
const hhmmss_1 = __importDefault(require("./lib/hhmmss"));
const lowdb_1 = require("@commonify/lowdb");
const hhmmss_1 = __importDefault(require("./lib/hhmmss"));
const DATA_PATH = process.env.DATA_PATH || './data/';
const DBG = Boolean(process.env.DBG || false);
const adapter = new lowdb_1.JSONFile(DATA_PATH + 'telegram.json');
const db = new lowdb_1.Low(adapter);
const serverInfoMessages = [];
@@ -15,14 +16,21 @@ let bot;
async function init(token) {
console.log('telegram-bot starting...');
bot = new grammy_1.Bot(token);
bot.catch(e => {
console.error('telegram-bot ERROR', e.message || e);
});
const me = await bot.api.getMe();
console.log('telegram-bot ready', me);
// bot.on('message:text', ctx => {ctx.reply('echo: ' + ctx.message.text);});
// bot.command('start', ctx => ctx.reply('cmd.start.response'));
// bot.start();
if (DBG) {
bot.on('message:text', ctx => {
if (ctx.message.text === 'ping')
ctx.reply('pong');
});
// bot.command('ping', ctx => ctx.reply('/pong'));
bot.start();
}
await db.read();
db.data = db.data || [];
return;
}
exports.init = init;
async function getServerInfoMessage(cid, host, port) {
@@ -46,42 +54,11 @@ async function getServerInfoMessage(cid, host, port) {
return m;
}
async function serverUpdate(gs) {
var _a, _b, _c, _d;
if (!gs.info)
return;
console.log('telegram.serverUpdate', gs.config.host, gs.config.port, gs.config.telegram);
if (DBG)
console.log('telegram.serverUpdate', gs.config.host, gs.config.port, gs.config.telegram);
for (const cid of gs.config.telegram.chatIds) {
let m = await getServerInfoMessage(cid, gs.config.host, gs.config.port);
const stats = gs.history.stats();
let statsText = '';
if (stats.length > 0) {
const s = stats.pop();
if (s) {
statsText = ' (hourly max: ' + s.max + ', hourly avg: ' + s.avg.toFixed(1) + ')';
}
}
const infoText = [
gs.niceName,
gs.info.game + ' / ' + gs.info.map,
gs.info.connect,
'Players ' + gs.info.playersNum + '/' + gs.info.playersMax + statsText
];
if (((_a = gs.info) === null || _a === void 0 ? void 0 : _a.players.length) > 0) {
infoText.push('```');
for (const p of (_b = gs.info) === null || _b === void 0 ? void 0 : _b.players) {
let playerLine = '';
if (((_c = p.raw) === null || _c === void 0 ? void 0 : _c.time) !== undefined) {
playerLine += '[' + (0, hhmmss_1.default)(p.raw.time) + '] ';
}
playerLine += p.name;
if (((_d = p.raw) === null || _d === void 0 ? void 0 : _d.score) !== undefined) {
playerLine += ' [score: ' + p.raw.score + ']';
}
infoText.push(playerLine);
}
infoText.push('```');
}
m.setText(infoText.join('\n'));
m.updatePost(gs);
}
}
exports.serverUpdate = serverUpdate;
@@ -118,10 +95,42 @@ class ServerInfoMessage {
await db.write();
}
}
async setText(text) {
console.log('setText', this.host, this.port);
async updatePost(gs) {
var _a, _b;
let infoText = gs.niceName + ' offline...';
if (gs.info && gs.online) {
const stats = gs.history.stats();
let statsText = '';
if (stats.length > 0) {
const s = stats.slice(-1).pop();
if (s) {
statsText = ' (hourly avg/max: ' + s.avg.toFixed(1) + '/' + s.max + ') ';
}
}
infoText = [
gs.niceName,
gs.info.game + ' / ' + gs.info.map,
gs.info.connect,
'Players ' + gs.info.playersNum + '/' + gs.info.playersMax + statsText
].join('\n');
if (gs.info.players.length > 0 && gs.info.players[0].name !== undefined) {
const pnArr = [];
for (const p of gs.info.players) {
let playerLine = '';
if (((_a = p.raw) === null || _a === void 0 ? void 0 : _a.time) !== undefined) {
playerLine += (0, hhmmss_1.default)(p.raw.time) + ' ';
}
playerLine += p.name;
if (((_b = p.raw) === null || _b === void 0 ? void 0 : _b.score) !== undefined) {
playerLine += ' (' + p.raw.score + ')';
}
pnArr.push(playerLine);
}
infoText += '```\n' + pnArr.join('\n').slice(0, 4088 - infoText.length) + '\n```';
}
}
try {
await bot.api.editMessageText(this.chatId, this.messageId, text, { parse_mode: 'Markdown' });
await bot.api.editMessageText(this.chatId, this.messageId, infoText, { parse_mode: 'Markdown' });
}
catch (e) {
console.log(e.message || e);

View File

@@ -1,9 +1,10 @@
import { Bot } from 'grammy';
import { Low, JSONFile } from '@commonify/lowdb';
import { GameServer } from './game-server';
import hhmmss from './lib/hhmmss';
import { Low, JSONFile } from '@commonify/lowdb';
const DATA_PATH = process.env.DATA_PATH || './data/';
const DBG = Boolean(process.env.DBG || false);
interface TelegramData {
chatId: string;
@@ -22,17 +23,24 @@ export async function init(token: string) {
console.log('telegram-bot starting...');
bot = new Bot(token);
bot.catch(e => {
console.error('telegram-bot ERROR', e.message || e);
});
const me = await bot.api.getMe();
console.log('telegram-bot ready', me);
// bot.on('message:text', ctx => {ctx.reply('echo: ' + ctx.message.text);});
// bot.command('start', ctx => ctx.reply('cmd.start.response'));
// bot.start();
if(DBG) {
bot.on('message:text', ctx => {
if (ctx.message.text === 'ping')
ctx.reply('pong');
});
// bot.command('ping', ctx => ctx.reply('/pong'));
bot.start();
}
await db.read();
db.data = db.data || [];
return;
}
async function getServerInfoMessage(cid: string, host: string, port: number) {
@@ -62,46 +70,11 @@ async function getServerInfoMessage(cid: string, host: string, port: number) {
}
export async function serverUpdate(gs: GameServer) {
if (!gs.info) return;
console.log('telegram.serverUpdate', gs.config.host, gs.config.port, gs.config.telegram);
if (DBG) console.log('telegram.serverUpdate', gs.config.host, gs.config.port, gs.config.telegram);
for (const cid of gs.config.telegram.chatIds) {
let m = await getServerInfoMessage(cid, gs.config.host, gs.config.port);
const stats = gs.history.stats();
let statsText = '';
if (stats.length > 0) {
const s = stats.pop();
if (s) {
statsText = ' (hourly max: ' + s.max + ', hourly avg: ' + s.avg.toFixed(1) + ')';
}
}
const infoText: string[] = [
gs.niceName,
gs.info.game + ' / ' + gs.info.map,
gs.info.connect,
'Players ' + gs.info.playersNum + '/' + gs.info.playersMax + statsText
];
if (gs.info?.players.length > 0) {
infoText.push('```');
for(const p of gs.info?.players) {
let playerLine = '';
if (p.raw?.time !== undefined) {
playerLine += '[' + hhmmss(p.raw.time) + '] ';
}
playerLine += p.name;
if (p.raw?.score !== undefined) {
playerLine += ' [score: ' + p.raw.score + ']';
}
infoText.push(playerLine);
}
infoText.push('```');
}
m.setText(infoText.join('\n'));
m.updatePost(gs);
}
}
@@ -145,10 +118,45 @@ class ServerInfoMessage {
}
}
async setText(text: string) {
console.log('setText', this.host, this.port);
async updatePost(gs: GameServer) {
let infoText = gs.niceName + ' offline...';
if (gs.info && gs.online) {
const stats = gs.history.stats();
let statsText = '';
if (stats.length > 0) {
const s = stats.slice(-1).pop();
if (s) {
statsText = ' (hourly avg/max: ' + s.avg.toFixed(1) + '/' + s.max + ') ';
}
}
infoText = [
gs.niceName,
gs.info.game + ' / ' + gs.info.map,
gs.info.connect,
'Players ' + gs.info.playersNum + '/' + gs.info.playersMax + statsText
].join('\n');
if (gs.info.players.length > 0 && gs.info.players[0].name !== undefined) {
const pnArr: string[] = [];
for(const p of gs.info.players) {
let playerLine = '';
if (p.raw?.time !== undefined) {
playerLine += hhmmss(p.raw.time) + ' ';
}
playerLine += p.name;
if (p.raw?.score !== undefined) {
playerLine += ' (' + p.raw.score + ')';
}
pnArr.push(playerLine);
}
infoText += '```\n' + pnArr.join('\n').slice(0, 4088 - infoText.length) + '\n```';
}
}
try {
await bot.api.editMessageText(this.chatId, this.messageId, text, {parse_mode: 'Markdown'});
await bot.api.editMessageText(this.chatId, this.messageId, infoText, {parse_mode: 'Markdown'});
} catch (e: any) {
console.log(e.message || e);
}

View File

@@ -1,7 +1,11 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
@@ -25,10 +29,11 @@ const discordBot = __importStar(require("./discord-bot"));
const telegramBot = __importStar(require("./telegram-bot"));
const fs_1 = require("fs");
const { readFile } = fs_1.promises;
const REFRESH_TIME_MINUTES = parseInt(process.env.REFRESH_TIME_MINUTES || '1', 10);
const REFRESH_TIME_MINUTES = parseInt(process.env.REFRESH_TIME_MINUTES || '5', 10);
const DISCORD_BOT_TOKEN = process.env.DISCORD_BOT_TOKEN || '';
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN || '';
const GSW_CONFIG = process.env.GSW_CONFIG || './config/default.config.json';
const DBG = Boolean(process.env.DBG || false);
class Watcher {
constructor() {
this.servers = [];
@@ -47,8 +52,9 @@ class Watcher {
this.servers.push(gs);
}
}
check() {
console.log('watcher checking...');
async check() {
if (DBG)
console.log('watcher checking...');
const promises = [];
for (const gs of this.servers) {
promises.push(gs.update().then(() => {
@@ -60,24 +66,20 @@ class Watcher {
}
}));
}
return Promise.allSettled(promises).then(() => (0, game_server_1.saveDb)());
await Promise.allSettled(promises);
await (0, game_server_1.saveDb)();
}
}
let loop = null;
async function main() {
console.log('reading config...', GSW_CONFIG);
console.log('reading config', GSW_CONFIG);
const buffer = await readFile(GSW_CONFIG);
console.log('buffer', buffer.toString());
try {
const conf = JSON.parse(buffer.toString());
const watcher = new Watcher();
await watcher.init(conf);
console.log('starting loop...', REFRESH_TIME_MINUTES);
loop = setInterval(async () => { await watcher.check(); }, 1000 * 60 * REFRESH_TIME_MINUTES);
await watcher.check();
} catch (e) {
console.error(e.message || e);
}
// return watcher;
}
exports.main = main;

View File

@@ -5,10 +5,11 @@ import * as telegramBot from './telegram-bot';
import { promises as fs } from 'fs';
const { readFile } = fs;
const REFRESH_TIME_MINUTES = parseInt(process.env.REFRESH_TIME_MINUTES || '1', 10);
const REFRESH_TIME_MINUTES = parseInt(process.env.REFRESH_TIME_MINUTES || '5', 10);
const DISCORD_BOT_TOKEN = process.env.DISCORD_BOT_TOKEN || '';
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN || '';
const GSW_CONFIG = process.env.GSW_CONFIG || './config/default.config.json';
const DBG = Boolean(process.env.DBG || false);
export interface WatcherConfig {
host: string;
@@ -45,8 +46,8 @@ class Watcher {
}
}
check() {
console.log('watcher checking...');
async check() {
if (DBG) console.log('watcher checking...');
const promises: Promise<void>[] = [];
for (const gs of this.servers) {
@@ -61,13 +62,14 @@ class Watcher {
}));
}
return Promise.allSettled(promises).then(() => saveDb());
await Promise.allSettled(promises);
await saveDb();
}
}
let loop = null;
export async function main() {
console.log('reading config...', GSW_CONFIG);
console.log('reading config', GSW_CONFIG);
const buffer = await readFile(GSW_CONFIG);
const conf = JSON.parse(buffer.toString());