1
0
mirror of https://github.com/mgerb/ServerStatus synced 2026-01-11 11:42:50 +00:00

4 Commits

Author SHA1 Message Date
56770b7b66 v0.7.0 2020-06-10 18:30:40 -05:00
f8d72bc297 feat: new features/improvements
- update dependencies
- add up/down time #14
- add workers with retry to help with spam
2020-06-10 18:28:41 -05:00
68bfed3f3b update readme 2019-01-19 20:30:27 -06:00
92d94ed4d4 feat(RCON): added RCON support for UDP servers 2019-01-19 20:13:55 -06:00
10 changed files with 152 additions and 49 deletions

65
Gopkg.lock generated
View File

@@ -1,41 +1,90 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:05eebdd5727fea23083fce0d98d307d70c86baed644178e81608aaa9f09ea469"
name = "github.com/Sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "60c74ad9be0d874af0ab0daef6ab07c5c5911f0d"
version = "v1.6.0"
[[projects]]
branch = "master"
digest = "1:b7e05c8da029b985907b15e126cde5f42f2814b08211a184dac436eeec6fe780"
name = "github.com/anvie/port-scanner"
packages = [
".",
"predictors",
"predictors/webserver"
"predictors/webserver",
]
pruneopts = "UT"
revision = "8159197d3770eb6dbf3a9706a6d40462ebb69cec"
[[projects]]
digest = "1:d87c9221a974263e3b369bfd3513707b2a53e27a6cd799d472f94dc6a6157e59"
name = "github.com/bwmarrin/discordgo"
packages = ["."]
revision = "4a33b9bc7c56cfdb9bb244e33e83cb3941fe2bdc"
version = "v0.18.0"
pruneopts = "UT"
revision = "ed4d6904961d1688b3f5601b3d73e95a71046734"
version = "v0.20.3"
[[projects]]
digest = "1:6d29f02f0f01c627c2be40fb7347669a9ff2aa215cb97747294c1d13ffa74bdd"
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
pruneopts = "UT"
revision = "b65e62901fc1c0d968042419e74789f6af455eb9"
version = "v1.4.2"
[[projects]]
branch = "master"
digest = "1:50993a8fbb3042b88dfecb8f4473a42f13ac70d6fd86f64df525a28b357c2d5b"
name = "github.com/kidoman/go-steam"
packages = ["."]
pruneopts = "UT"
revision = "2e40e0d508cbac591bab4ae18b231153295f3a0a"
[[projects]]
digest = "1:09cb61dc19af93deae01587e2fdb1c081e0bf48f1a5ad5fa24f48750dc57dce8"
name = "github.com/konsorten/go-windows-terminal-sequences"
packages = ["."]
pruneopts = "UT"
revision = "edb144dfd453055e1e49a3d8b410a660b5a87613"
version = "v1.0.3"
[[projects]]
branch = "master"
digest = "1:1714bd928fd176237ccdea21695bf72801c1ee5f51bccefb69b87f0fd376a6aa"
name = "golang.org/x/crypto"
packages = [
"internal/subtle",
"nacl/secretbox",
"poly1305",
"salsa20/salsa"
"salsa20/salsa",
]
revision = "c4a91bd4f524f10d064139674cf55852e055ad01"
pruneopts = "UT"
revision = "70a84ac30bf957c7df57edd1935d2081871515e1"
[[projects]]
branch = "master"
digest = "1:145abe7dfa46d17ef35e5126ed1cc87b9100e78b9f428c9460deea34bfeabafb"
name = "golang.org/x/sys"
packages = [
"cpu",
"internal/unsafeheader",
"unix",
]
pruneopts = "UT"
revision = "226ff32320da7b90d0b5bc2365f4e359c466fb78"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "0832269100c492c595c4fe5f02e10d70889b9fa4d6a869c3ad59584cda0c5d31"
input-imports = [
"github.com/anvie/port-scanner",
"github.com/bwmarrin/discordgo",
"github.com/kidoman/go-steam",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -31,8 +31,12 @@
[[constraint]]
name = "github.com/bwmarrin/discordgo"
version = "0.18.0"
version = "0.20.0"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/kidoman/go-steam"

View File

@@ -4,6 +4,7 @@
"RolesToNotify": ["<@&roleid>", "<@userid>"],
"GameStatus": "current playing game",
"PollingInterval": 10,
"BotPrefix": "!",
"Servers": [
{
"Name": "Your awesome server",

View File

@@ -16,16 +16,20 @@ type configStruct struct {
Token string `json:"Token"`
RoomIDList []string `json:"RoomIDList"`
RolesToNotify []string `json:"RolesToNotify"`
Servers []server `json:"Servers"`
Servers []Server `json:"Servers"`
GameStatus string `json:"GameStatus"`
PollingInterval time.Duration `json:"PollingInterval"`
BotPrefix string `json:"BotPrefix"`
}
type server struct {
type Server struct {
Name string `json:"Name"`
Address string `json:"Address"`
Port int `json:"Port"`
Online bool `json:"Online,omitempty"`
// OnlineTimestamp - time of when the server last came online
OnlineTimestamp time.Time
OfflineTimestamp time.Time
}
func Configure() {

View File

@@ -8,11 +8,6 @@ import (
"github.com/mgerb/ServerStatus/serverstatus"
)
// Variables used for command line parameters
var (
BotID string
)
var version = "undefined"
func init() {

View File

@@ -4,7 +4,7 @@ run:
go run ./src/main.go
linux:
go build -o ./dist/ServerStatus-linux -ldflags="-X main.version=${VERSION}" ./main.go
GOOS=linux GOARCH=amd64 go build -o ./dist/ServerStatus-linux -ldflags="-X main.version=${VERSION}" ./main.go
mac:
GOOS=darwin GOARCH=amd64 go build -o ./dist/ServerStatus-mac -ldflags="-X main.version=${VERSION}" ./main.go

View File

@@ -1,21 +1,18 @@
# Server Status
Scans a list of TCP servers checking checking which are currently online.
This bot will send a chat notification when the status of a server changes (goes on or offline).
Monitors a list of servers and sends a chat notification when a server goes on or offline.
I originally made this bot to check if private World of Warcraft servers were up or not.
It's actually much more useful than that and can be used for most servers.
NOTE: This bot currently does not have any UDP support.
- **TCP** - should work with all servers
- **UDP** - [Source RCON Protocol](https://developer.valvesoftware.com/wiki/Source_RCON_Protocol) is supported
## Configuration
- Download the latest release [here](https://github.com/mgerb/ServerStatus/releases)
- Add your bot token as well as other configurations to config.json
- Add your bot token as well as other configurations to **config.json**
- Execute the OS specific binary!
### Mentioning Roles/Users
- you must first get your role/user id
- for user `<@userid>`
- for role `<@&roleid>`
- list of user/role ID's must be in the following format (see below for obtaining ID's)
- `<@userid>`
- `<@&roleid>`
### Polling Interval
The polling interval is how often the bot will try to ping the servers.
@@ -23,7 +20,7 @@ A good interval is 10 seconds, but this may need some adjustment if
it happens to be spamming notifications.
- time in seconds
- configurable in `config.json`
- configurable in **config.json**
## With Docker
@@ -46,7 +43,7 @@ services:
## Usage
To get the current status of your servers simply type `!ServerStatus` in chat.
![Server Status](https://i.imgur.com/ZzQSBJp.png)
![Server Status](./readme_files/screenshot1.png)
## Compiling from source
- Make sure Go and Make are installed
@@ -58,5 +55,4 @@ https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-
### How to get your room ID
To get IDs, turn on Developer Mode in the Discord client (User Settings -> Appearance) and then right-click your name/icon anywhere in the client and select Copy ID.
<img src="https://camo.githubusercontent.com/9f759ec8b45a6e9dd2242bc64c82897c74f84a25/687474703a2f2f692e696d6775722e636f6d2f47684b70424d512e676966"/>
<img src="./readme_files/screenshot2.gif"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

View File

@@ -1,12 +1,16 @@
package serverstatus
import (
"fmt"
"log"
"strconv"
"strings"
"sync"
"time"
"github.com/anvie/port-scanner"
portscanner "github.com/anvie/port-scanner"
"github.com/bwmarrin/discordgo"
steam "github.com/kidoman/go-steam"
"github.com/mgerb/ServerStatus/bot"
"github.com/mgerb/ServerStatus/config"
)
@@ -22,6 +26,8 @@ func Start() {
//set each server status as online to start
for i := range config.Config.Servers {
config.Config.Servers[i].Online = true
config.Config.Servers[i].OnlineTimestamp = time.Now()
config.Config.Servers[i].OfflineTimestamp = time.Now()
}
err := bot.Session.UpdateStatus(0, config.Config.GameStatus)
@@ -46,36 +52,74 @@ func scanServers() {
for {
for index, server := range config.Config.Servers {
prevServerUp := server.Online //set value to previous server status
// use waitgroup to scan all servers concurrently
var wg sync.WaitGroup
serverScanner := portscanner.NewPortScanner(server.Address, time.Second*2, 1)
serverUp := serverScanner.IsOpen(server.Port) //check if the port is open
if serverUp && serverUp != prevServerUp {
sendMessageToRooms(green, server.Name, "Is now online :smiley:", true)
} else if !serverUp && serverUp != prevServerUp {
sendMessageToRooms(red, server.Name, "Has gone offline :frowning2:", true)
}
config.Config.Servers[index].Online = serverUp
for index := range config.Config.Servers {
wg.Add(1)
go worker(index, &config.Config.Servers[index], &wg)
}
wg.Wait()
time.Sleep(time.Second * config.Config.PollingInterval)
}
}
func worker(index int, server *config.Server, wg *sync.WaitGroup) {
defer wg.Done()
prevServerUp := server.Online //set value to previous server status
var serverUp bool
retryCounter := 0
// try reconnecting 5 times if failure persists (every 2 seconds)
for {
serverScanner := portscanner.NewPortScanner(server.Address, time.Second*2, 1)
serverUp = serverScanner.IsOpen(server.Port) //check if the port is open
if serverUp || retryCounter >= 5 {
break
}
retryCounter++
time.Sleep(time.Second * 2)
}
// if server isn't up check RCON protocol (UDP)
if !serverUp {
host := server.Address + ":" + strconv.Itoa(server.Port)
steamConnection, err := steam.Connect(host)
if err == nil {
defer steamConnection.Close()
_, err := steamConnection.Ping()
if err == nil {
serverUp = true
}
}
}
if serverUp && serverUp != prevServerUp {
server.OnlineTimestamp = time.Now()
sendMessageToRooms(green, server.Name, "Is now online :smiley:", true)
} else if !serverUp && serverUp != prevServerUp {
server.OfflineTimestamp = time.Now()
sendMessageToRooms(red, server.Name, "Has gone offline :frowning2:", true)
}
server.Online = serverUp
}
func sendMessageToRooms(color int, title, description string, mentionRoles bool) {
for _, roomID := range config.Config.RoomIDList {
if mentionRoles {
content := strings.Join(config.Config.RolesToNotify, " ")
bot.Session.ChannelMessageSend(roomID, content)
}
sendEmbededMessage(roomID, color, title, description)
sendEmbeddedMessage(roomID, color, title, description)
}
}
func sendEmbededMessage(roomID string, color int, title, description string) {
func sendEmbeddedMessage(roomID string, color int, title, description string) {
embed := &discordgo.MessageEmbed{
Color: color,
@@ -95,13 +139,23 @@ func MessageHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
return
}
if m.Content == "!ServerStatus" {
if m.Content == config.Config.BotPrefix+"ServerStatus" {
for _, server := range config.Config.Servers {
if server.Online {
sendEmbededMessage(m.ChannelID, green, server.Name, "Online!")
sendEmbeddedMessage(m.ChannelID, green, server.Name, "Online!\nUptime: "+fmtDuration(time.Since(server.OnlineTimestamp)))
} else {
sendEmbededMessage(m.ChannelID, red, server.Name, "Offline!")
sendEmbeddedMessage(m.ChannelID, red, server.Name, "Offline!\nDowntime: "+fmtDuration(time.Since(server.OfflineTimestamp)))
}
}
}
}
func fmtDuration(d time.Duration) string {
days := int(d.Hours()) / 24
hours := int(d.Hours()) % 60
minutes := int(d.Minutes()) % 60
seconds := int(d.Seconds()) % 60
return fmt.Sprintf("%dd %dh %dm %ds", days, hours, minutes, seconds)
}