debug, readme, config

This commit is contained in:
Smith
2022-04-18 16:49:13 +02:00
parent 4f6884de02
commit 9bef000933
9 changed files with 383 additions and 83 deletions

292
README.md
View File

@@ -1,25 +1,44 @@
# game-server-watcher
Requirements: [node.js](https://nodejs.org/) _(version 12.20.0 or later)_
# Game Server Watcher
A simple discord/telegram bot that can be hosted on a free service to monitor your game servers and players in style. 😎
# Configuration
//TODO: env vars (`.env` file supported); check [default.env](./default.env)
//TODO: [config files](./config/default.config.json) schema description
## Table of Contents
1. [About the Project](#about-the-project)
1. [Project Status](#project-status)
1. [Getting Started](#getting-started)
1. [Requirements](#requirements)
1. [Installation](#installation)
1. [Usage](#usage)
1. [Configuration](#configuration)
1. [Managing the service](#managing-the-service)
1. [Deployment](#deployment)
1. [How to Get Help](#how-to-get-help)
1. [Further Reading](#further-reading)
1. [Contributing](#contributing)
1. [License](#license)
1. [Authors](#authors)
1. [Acknowledgments](#acknowledgments)
### Starting the service
Install dependencies: `npm i`
Build & start program: `npm start`
## The goals of this repo
# About the Project
The main goals of this repo:
1. create a (simple, but capable) service/bot to monitor game servers
1. get gamedig & steam api server info (_eg.: server name, map, players, etc._)
1. relay real time server information to various channels via APIs (_eg.: discord, telegram, slack etc._)
1. should be able to host on a free service (_target atm. is cloudno.de (nodejs 12.20.1)_)
1. graciously add more features based on community feedback
1. graciously add more features based on community feedback ([discord](https://discord.gg/4tsbftsGJz) / [github](https://github.com/a-sync/game-server-watcher/issues/new))
Get support on [discord](https://discord.gg/4tsbftsGJz) or on [github](https://github.com/a-sync/game-server-watcher/issues/new).
More detailed customization options and additional features will be added as requested.
## Screenshots
### Discord
![discord](https://user-images.githubusercontent.com/14183614/162092529-e1645b44-2650-4893-8123-7ba187b1f51c.png)
[SCREENSHOTS](https://github.com/a-sync/game-server-watcher/issues/1#issue-1195221880)
### Telegram
![telegram](https://user-images.githubusercontent.com/14183614/162092488-f28bd60c-88bf-4b1e-a31e-d7dca51d8c28.png)
**[Back to top](#table-of-contents)**
# Project Status
The code itself is stable and continuously tested/deployed from the cloud branch.
The project is in a very early stage. More detailed customization options and additional features will be added as requested.
### Possible features and configuration options to add in the future
* optional player list
@@ -35,75 +54,202 @@ More detailed customization options and additional features will be added as req
* more integrations: slack, ms teams, twillio (email, sms)
* web ui to manage & configure the servers and bots
* put custom information in the channel name (online status indicator, number of players, map)
* github action workflows to deploy to other cloud providers (azure, aws cdk, etc.)
# Self host on cloudno.de
You can fork (copy) this repo on github, and automatically deploy your configuration or other changes as a cloud service.
**[Back to top](#table-of-contents)**
## Part 1: create and setup [cloudno.de](https://cloudno./de) repo
1. register account
1. create app: https://cloudno.de/myapps?new (make sure to set the latest node.js version and leave server.js as entry point)
1. provision app
1. copy https git URL from app
1. go to profile and save your token (https://cloudno.de/account --> API tokens)
1. add username and token as authentication to the URL like this: `https://username:secrettoken@git.cloudno.de/git/username/xyz`; save it for later use on (github)
1. go to application --> manage --> environment
1. set `DATA_PATH=/mnt/` in cloud app env
1. go to the forked repo on github: settings --> secrets --> actions and setup `CLOUDNODE_REPO_URL` secret with the full URL
# Getting Started
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
## Part 2 (optional): create and invite discord bot and get token
1. create app (https://discord.com/developers/applications)
1. create bot
1. under the bots name you should seee a token or an option to reset token
1. check message content intent
1. oauth2 --> url generator --> check bot as scopes; create bot invite link with permissions: view channels, send messages, message history, embed links, add reaction (85056),
1. invite bot to servers (guilds)
1. create bot auth token, copy it
1. setup `DISCORD_BOT_TOKEN` in cloud app env
1. //CONFIG: find and copy then setup channel ids in config
## Requirements
[node.js](https://nodejs.org/) _(version 12.20.0 or later)_
## Part 3 (optional): create telegram bot and get token
//TODO: get token from [botfather](https://t.me/botfather) and setup as `TELEGRAM_BOT_TOKEN` in cloud app env; get chat id from [getidsbot](https://t.me/getidsbot) and setup chat ids in config
## Getting the Source
This project is [hosted on github](https://github.com/a-sync/game-server-watcher). You can clone this project directly using this command:
## Part 4 (optional): create steam web api key
[Request a web api key](https://steamcommunity.com/dev/apikey) and configure it as `STEAM_WEB_API_KEY` in cloud app env; set appId fields in config
```
git clone git@github.com:a-sync/game-server-watcher.git
```
## Part 5: create and setup github repo
1. hit fork button
1. repo settings page --> actions --> general: allow all actions (if no confirmation comes up, disable then re-enable all actions)
The latest source and build can also be downloaded as a [zip archive](https://github.com/a-sync/game-server-watcher/archive/refs/heads/master.zip).
## Part 6: edit `cloud` branch, configure and deploy the service
_**Protip:** Use the dot (**.**) key to open your code in github.dev web-based editor when browsing github!_
1. switch to the `cloud` branch of your fork; (`git checkout -b cloud`)
1. create a new config file (and setup `GSW_CONFIG` in cloud app env to point to it) or edit config/default.config.json and save it
1. commit and push your changes (`git add . && git commit -m :shipit: && git push origin cloud`)
## Installation
Use npm or yarn to install/update all the dependencies.
You can also just use the _edit this file_ button to make changes to the default config file, just make sure to switch to the `cloud` branch to have it automatically deployed.
Commiting your changes and pushing your commits to github will trigger github actions to push your files to cloudno.de and restart the service.
# Manage
A few web endpoints are available to clear out service data.
Make sure to configure a proper `SECRET` env var to enable these!
### Servers `/flush/servers/SECRET`
Removes all stored game server data:
* population history configured by `PLAYERS_HISTORY_HOURS`
### Telegram `/flush/telegram/SECRET`
The bot has no cleanup functionality, left over messages must be removed manually.
If the original message created by the bot gets deleted, you need to flush the bot data to reinitialize the message.
### Discord `/flush/discord/SECRET`
The bot has no cleanup functionality, left over messages must be removed manually.
If the original message created by the bot gets deleted, you might need to flush the bot data to reinitialize the message.
# Development
## Running locally
```
npm i
```
If you don't need to build the source, you can skip development dependencies.
```
npm i --only=prod
```
## Usage
Build the source and start the service in one command.
```
npm start
```
Build, start and auto restart on source changes.
```
npm run dev
```
## Nodejs v12 dependency limitations
* [discord.js v12](https://discord.js.org/#/docs/discord.js/v12/general/welcome) (discord API v8)
* got v11
## Configuration
The watcher service can be configured via environmental variables. `.env` ([dotenv](https://www.npmjs.com/package/dotenv)) file is also supported, for avaialable values and defaults check the [default.env](./default.env) file.
Refer to the wiki on how to get tokens for:
* [steam](https://github.com/a-sync/game-server-watcher/wiki/Steam-Web-API-key)
* [discord](https://github.com/a-sync/game-server-watcher/wiki/Discord-bot-token)
* [telegram](https://github.com/a-sync/game-server-watcher/wiki/Telegram-bot-token)
### Config file schema
The game server and bot configurations are stored in JSON files.
The path of the config file used is defined by the `GSW_CONFIG` env var. (default: [./config/default.config.json](./config/default.config.json))
The config file must be a valid JSON file that holds a list (array) of game server configuration objects.
```json
[
{
"host": "0.0.0.0",
"port": 0,
"type": "gamedigID",
"appId": 0,
"discord": {
"channelIds": []
},
"telegram": {
"chatIds": []
}
},
...
]
```
Each configuration object describes a game server (host, port, gamedig id, steam app id) and all the bots options for that game server. (discord channel IDs, telegram chat IDs)
#### host
String. Can be a domain name or IP.
#### port
Number. The port used by the game server instance.
#### type
String. Gamedig ID from the [supported games list](https://raw.githubusercontent.com/a-sync/node8-gamedig/master/games.txt).
#### appId
Number. Steam app ID from [steamdb](https://steamdb.info/apps/).
_Only used if you have `STEAM_WEB_API_KEY` configured and only as backup. Set it to `0` if you don't need it._
#### discord.channelIds
String array. List of discord channel IDs.
_Only used if you have `DISCORD_BOT_TOKEN` configured._
#### telegram.chatIds
String array. List of telegram chat IDs.
_Only used if you have `TELEGRAM_BOT_TOKEN` configured._
## Managing the service
A few web endpoints are available to clear out service data.
Make sure to configure a proper `SECRET` env var to enable these!
### Servers data
GET `/flush/servers/SECRET`
Removes population history data. (configured by `PLAYERS_HISTORY_HOURS`)
### Telegram data
GET `/flush/telegram/SECRET`
If the original message created by the bot gets deleted, you need to flush the bot data to reinitialize the message.
The bot has no cleanup functionality, left over messages must be removed manually.
### Discord data
GET `/flush/discord/SECRET`
If the original message created by the bot gets deleted, you might need to flush the bot data to reinitialize the message.
The bot has no cleanup functionality, left over messages must be removed manually.
**[Back to top](#table-of-contents)**
# Deployment
Check the wiki page for detailed instructions on [how to setup a self deploying free cloud instance at cloudno.de](https://github.com/a-sync/game-server-watcher/wiki/Free-hosting-via-cloudno.de).
## Hosting
Make sure all the requirements are met!
_**Protip:** check the node.js version with `node -v`._
### Build artifacts (optional)
```
npm i
npm run build
```
### Minimum required files on host
Copy the `./package.json` and `index.html` files and the `./dist/` folder to your deployment folder.
### Install production dependencies on host
Navigate to the deployment folder and execute the following command:
```
npm i --only=prod
```
### Configuration
Create a writeable folder for the data storage. (configured by `DATA_PATH` env var, default: `./data/`)
Create a configuration file. (configured by `GSW_CONFIG`, default: `./config/default.config.json`)
### Running
Run the program from the deployment folder:
```
node ./dist/server.js
```
**[Back to top](#table-of-contents)**
# How to Get Help
* Join the support / test [discord](https://discord.gg/4tsbftsGJz)
* Check the [wiki](https://github.com/a-sync/game-server-watcher/wiki)
* Ask a [question](https://github.com/a-sync/game-server-watcher/discussions/new?category=q-a)
**[Back to top](#table-of-contents)**
# Further Reading
* [gamedig supported games list](https://raw.githubusercontent.com/a-sync/node8-gamedig/master/games.txt)
* [steam web API documentation](https://steamapi.xpaw.me/#IGameServersService/GetServerList)
* [discord API v8 documentation](https://discord.js.org/#/docs/discord.js/v12/class/MessageEmbed)
* [telegram API documentation](https://core.telegram.org/bots/api#editmessagetext)
* [JSON validator](https://jsonformatter.org/)
* [steamDB](https://steamdb.info/apps/)
**[Back to top](#table-of-contents)**
# Contributing
Public contributions are welcome!
Create a [new issue](https://github.com/a-sync/game-server-watcher/issues/new) for bugs, or open a [pull request](https://github.com/a-sync/game-server-watcher/pulls) for any and all your changes.
**[Back to top](#table-of-contents)**
# License
This project is licensed under the AGPL License - see [LICENSE](./LICENSE) file for details.
**[Back to top](#table-of-contents)**
# Authors
Check the list of [contributors](https://github.com/a-sync/game-server-watcher/contributors) who participated in this project.
**[Back to top](#table-of-contents)**
# Acknowledgments
This project was inpired by (the sudden disappearance of) "_Game Status#5371_" bot and its creator [Ramzi Saheb](https://github.com/Ramzi-Sah) on discord.
The IP regex was stolen from the [ip-regex](https://github.com/sindresorhus/ip-regex) package source.
## Similar projects
https://github.com/soulkobk/DiscordBot_GameStatus
https://github.com/discord-gamestatus/discord-gamestatus
https://github.com/Ramzi-Sah/game-status-discordbot
https://github.com/Ramzi-Sah/game-status-discordbot-selfhosted
**[Back to top](#table-of-contents)**

View File

@@ -126,5 +126,131 @@
"325831302"
]
}
},
{
"host": "51.195.60.161",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493493650817024"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "135.125.188.105",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493493650817024"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "95.111.240.225",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493493650817024"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "51.195.209.188",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493409819283466"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "51.195.56.191",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493409819283466"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "135.125.140.176",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493409819283466"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "135.125.140.177",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493409819283466"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "51.195.68.16",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493409819283466"
]
},
"telegram": {
"chatIds": []
}
},
{
"host": "198.244.131.161",
"port": 2302,
"type": "arma3",
"appId": 107410,
"discord": {
"channelIds": [
"965493409819283466"
]
},
"telegram": {
"chatIds": []
}
}
]

View File

@@ -10,9 +10,7 @@
]
},
"telegram": {
"chatIds": [
""
]
"chatIds": []
}
}
]

View File

@@ -1,11 +1,22 @@
DBG=1
# Enable debug mode
DBG=0
# Game server info refresh interval in minutes
REFRESH_TIME_MINUTES=5
# Player population history max. length in hours
PLAYERS_HISTORY_HOURS=12
# The game server configuration file
GSW_CONFIG=./config/default.config.json
# Writeable folder for data storage
DATA_PATH=./data/
SECRET=secret
# Admin secret
SECRET=
# Web service host
APP_HOST=localhost
# Web service port
APP_PORT=8080
# Discord bot token
DISCORD_BOT_TOKEN=
# Telegram bot token
TELEGRAM_BOT_TOKEN=
# Steam web API key
STEAM_WEB_API_KEY=

12
dist/game-server.js vendored
View File

@@ -12,6 +12,7 @@ const getip_1 = __importDefault(require("./lib/getip"));
const STEAM_WEB_API_KEY = process.env.STEAM_WEB_API_KEY || '';
const PLAYERS_HISTORY_HOURS = parseInt(process.env.PLAYERS_HISTORY_HOURS || '12', 10);
const DATA_PATH = process.env.DATA_PATH || './data/';
const DBG = Boolean(process.env.DBG || false);
const adapter = new lowdb_1.JSONFile(DATA_PATH + 'servers.json');
const db = new lowdb_1.Low(adapter);
async function initDb() {
@@ -39,11 +40,20 @@ class GameServer {
this._niceName = config.host + ':' + config.port;
}
async update() {
if (DBG)
console.log('gs.up', this.config.host, this.config.port);
let info = await this.gamedig();
if (!info && STEAM_WEB_API_KEY) {
if (DBG)
console.log('gs.gamedig', info);
if (!info && STEAM_WEB_API_KEY && this.config.appId) {
info = await this.steam();
if (DBG)
console.log('gs.steam', info);
}
if (info) {
if (info.players.length > 0 && DBG) {
console.log('gs.players.0', info.players[0]);
}
this.online = true;
this.info = info;
this.history.add(info);

2
dist/lib/ipregex.js vendored
View File

@@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// source: https://github.com/sindresorhus/ip-regex
const v4 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}';
const v6segment = '[a-fA-F\\d]{1,4}';
const v6 = `
@@ -14,6 +15,5 @@ const v6 = `
(?::(?:(?::${v6segment}){0,5}:${v4}|(?::${v6segment}){1,7}|:)) // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim();
// Pre-compile only the exact regexes because adding a global flag make regexes stateful
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`);
exports.default = v46Exact;

View File

@@ -5,7 +5,8 @@
"main": "src/server",
"scripts": {
"start": "tsc && node ./dist/server.js",
"dev": "nodemon -e ts --exec \"tsc --incremental && node ./dist/server.js || exit 1\""
"dev": "nodemon -e ts --exec \"tsc --incremental && node ./dist/server.js || exit 1\"",
"build": "tsc"
},
"keywords": [],
"author": "a-sync@devs.space",

View File

@@ -8,6 +8,7 @@ import { WatcherConfig } from './watcher';
const STEAM_WEB_API_KEY = process.env.STEAM_WEB_API_KEY || '';
const PLAYERS_HISTORY_HOURS = parseInt(process.env.PLAYERS_HISTORY_HOURS || '12', 10);
const DATA_PATH = process.env.DATA_PATH || './data/';
const DBG = Boolean(process.env.DBG || false);
interface GameServerDb {
population: {
@@ -64,13 +65,20 @@ export class GameServer {
}
async update() {
if (DBG) console.log('gs.up', this.config.host, this.config.port);
let info = await this.gamedig();
if (!info && STEAM_WEB_API_KEY) {
if (DBG) console.log('gs.gamedig', info);
if (!info && STEAM_WEB_API_KEY && this.config.appId) {
info = await this.steam();
if (DBG) console.log('gs.steam', info);
}
if (info) {
if (info.players.length > 0 && DBG) {
console.log('gs.players.0', info.players[0]);
}
this.online = true;
this.info = info;
this.history.add(info);

View File

@@ -1,3 +1,4 @@
// source: https://github.com/sindresorhus/ip-regex
const v4 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}';
const v6segment = '[a-fA-F\\d]{1,4}';
@@ -15,7 +16,6 @@ const v6 = `
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim();
// Pre-compile only the exact regexes because adding a global flag make regexes stateful
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`);
export default v46Exact;