1
0
mirror of https://github.com/mgerb/ServerStatus synced 2026-01-12 04:02:48 +00:00

6 Commits

Author SHA1 Message Date
92d94ed4d4 feat(RCON): added RCON support for UDP servers 2019-01-19 20:13:55 -06:00
d0cf0eae78 Merge pull request #23 from mgerb/development
added docker support
2018-10-04 19:10:23 -05:00
642ccc7bf5 added docker support 2018-10-04 19:07:30 -05:00
bcb57c72a3 add polling interval to configurations - resolves #15 2018-07-18 20:22:37 -05:00
1cd9f139c2 Merge pull request #13 from mgerb/mitchell
added embedded messages resolves #9
2018-03-15 21:07:58 -05:00
8d26fba95d added embedded messages resolves #9 2018-03-15 21:06:08 -05:00
14 changed files with 292 additions and 54 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
/vendor
/dist

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
config.json config.json
dist dist
vendor

17
Dockerfile Normal file
View File

@@ -0,0 +1,17 @@
FROM golang:1.11.1-alpine
WORKDIR /go/src/github.com/mgerb/ServerStatus
ADD . .
RUN apk add --no-cache git alpine-sdk
RUN go get -u github.com/golang/dep/cmd/dep
RUN dep ensure
RUN make linux
FROM alpine:3.8
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*
WORKDIR /server-status
COPY --from=0 /go/src/github.com/mgerb/ServerStatus/dist/ServerStatus-linux .
ENTRYPOINT ./ServerStatus-linux

89
Gopkg.lock generated Normal file
View File

@@ -0,0 +1,89 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8"
name = "github.com/Sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5"
version = "v1.3.0"
[[projects]]
branch = "master"
digest = "1:b7e05c8da029b985907b15e126cde5f42f2814b08211a184dac436eeec6fe780"
name = "github.com/anvie/port-scanner"
packages = [
".",
"predictors",
"predictors/webserver",
]
pruneopts = "UT"
revision = "8159197d3770eb6dbf3a9706a6d40462ebb69cec"
[[projects]]
digest = "1:4fd5ce7844c22e194005b9e12fee8adc70fb5ba0bbba9e1964d2e3d1f301d789"
name = "github.com/bwmarrin/discordgo"
packages = ["."]
pruneopts = "UT"
revision = "4a33b9bc7c56cfdb9bb244e33e83cb3941fe2bdc"
version = "v0.18.0"
[[projects]]
digest = "1:43dd08a10854b2056e615d1b1d22ac94559d822e1f8b6fcc92c1a1057e85188e"
name = "github.com/gorilla/websocket"
packages = ["."]
pruneopts = "UT"
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:50993a8fbb3042b88dfecb8f4473a42f13ac70d6fd86f64df525a28b357c2d5b"
name = "github.com/kidoman/go-steam"
packages = ["."]
pruneopts = "UT"
revision = "2e40e0d508cbac591bab4ae18b231153295f3a0a"
[[projects]]
digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
name = "github.com/konsorten/go-windows-terminal-sequences"
packages = ["."]
pruneopts = "UT"
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
version = "v1.0.1"
[[projects]]
branch = "master"
digest = "1:e035fb07be76ce6e4ce005add75491d9f0749403f595f153d6e2823a71c24149"
name = "golang.org/x/crypto"
packages = [
"nacl/secretbox",
"poly1305",
"salsa20/salsa",
"ssh/terminal",
]
pruneopts = "UT"
revision = "c4a91bd4f524f10d064139674cf55852e055ad01"
[[projects]]
branch = "master"
digest = "1:43cde116ff48f299eddb7e6515677e6d0a2c915854bb05a333877f07c3bb3033"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "11f53e03133963fb11ae0588e08b5e0b85be8be5"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/anvie/port-scanner",
"github.com/bwmarrin/discordgo",
"github.com/kidoman/go-steam",
]
solver-name = "gps-cdcl"
solver-version = 1

42
Gopkg.toml Normal file
View File

@@ -0,0 +1,42 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/anvie/port-scanner"
[[constraint]]
name = "github.com/bwmarrin/discordgo"
version = "0.18.0"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/kidoman/go-steam"

View File

@@ -1,8 +1,9 @@
{ {
"Token": "your bot token", "Token": "your bot token",
"RoomIDList":["room id list goes here"], "RoomIDList":["room id list goes here"],
"RoleToNotify": "@everyone", "RolesToNotify": ["<@&roleid>", "<@userid>"],
"GameStatus": "current playing game", "GameStatus": "current playing game",
"PollingInterval": 10,
"Servers": [ "Servers": [
{ {
"Name": "Your awesome server", "Name": "Your awesome server",

View File

@@ -2,20 +2,23 @@ package config
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"time"
) )
// Variables used for command line parameters // Variables used for command line parameters
var Config configStruct var Config configStruct
type configStruct struct { type configStruct struct {
Token string `json:"Token"` Token string `json:"Token"`
RoomIDList []string `json:"RoomIDList"` RoomIDList []string `json:"RoomIDList"`
RoleToNotify string `json:"RoleToNotify"` RolesToNotify []string `json:"RolesToNotify"`
Servers []server `json:"Servers"` Servers []server `json:"Servers"`
GameStatus string `json:"GameStatus"` GameStatus string `json:"GameStatus"`
PollingInterval time.Duration `json:"PollingInterval"`
} }
type server struct { type server struct {
@@ -27,7 +30,7 @@ type server struct {
func Configure() { func Configure() {
log.Println("Reading config file...") fmt.Println("Reading config file...")
file, e := ioutil.ReadFile("./config.json") file, e := ioutil.ReadFile("./config.json")
@@ -36,12 +39,14 @@ func Configure() {
os.Exit(1) os.Exit(1)
} }
log.Printf("%s\n", string(file))
err := json.Unmarshal(file, &Config) err := json.Unmarshal(file, &Config)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
if Config.PollingInterval == 0 {
log.Fatal("Please set your PollingInterval > 0 in your config file.")
}
} }

5
docker-build.sh Executable file
View File

@@ -0,0 +1,5 @@
version=$(git describe --tags)
docker build -t mgerb/server-status:latest .
docker tag mgerb/server-status:latest mgerb/server-status:$version

7
docker-compose.yml Normal file
View File

@@ -0,0 +1,7 @@
version: "2"
services:
server-status:
image: mgerb/server-status:latest
volumes:
- ./config.json:/server-status/config.json

5
docker-push.sh Executable file
View File

@@ -0,0 +1,5 @@
version=$(git describe --tags)
docker push mgerb/server-status:latest;
docker push mgerb/server-status:$version;

17
main.go
View File

@@ -1,15 +1,18 @@
package main package main
import ( import (
"github.com/mgerb/serverstatus/bot" "fmt"
"github.com/mgerb/serverstatus/config"
"github.com/mgerb/serverstatus/serverstatus" "github.com/mgerb/ServerStatus/bot"
"github.com/mgerb/ServerStatus/config"
"github.com/mgerb/ServerStatus/serverstatus"
) )
// Variables used for command line parameters var version = "undefined"
var (
BotID string func init() {
) fmt.Println("Starting Server Status " + version)
}
func main() { func main() {
//read config file //read config file

View File

@@ -1,14 +1,16 @@
VERSION := $(shell git describe --tags)
run: run:
go run ./src/main.go go run ./src/main.go
linux: linux:
go build -o ./dist/ServerStatus-linux ./main.go go build -o ./dist/ServerStatus-linux -ldflags="-X main.version=${VERSION}" ./main.go
mac: mac:
GOOS=darwin GOARCH=amd64 go build -o ./dist/ServerStatus-mac ./main.go GOOS=darwin GOARCH=amd64 go build -o ./dist/ServerStatus-mac -ldflags="-X main.version=${VERSION}" ./main.go
windows: windows:
GOOS=windows GOARCH=386 go build -o ./dist/ServerStatus-windows.exe ./main.go GOOS=windows GOARCH=386 go build -o ./dist/ServerStatus-windows.exe -ldflags="-X main.version=${VERSION}" ./main.go
clean: clean:
rm -rf ./dist rm -rf ./dist
@@ -16,4 +18,7 @@ clean:
copyfiles: copyfiles:
cp config.template.json ./dist/config.json cp config.template.json ./dist/config.json
zip:
zip -r dist.zip dist
all: linux mac windows copyfiles all: linux mac windows copyfiles

View File

@@ -1,24 +1,52 @@
## Server Status # Server Status
Scans a list of servers checking checking which are currently online.
Scans a list of servers checking whether the ports are open or not.
This bot will send a chat notification when the status of a server changes (goes on or offline). This bot will send a chat notification when the status of a server changes (goes on or offline).
I originally made this bot to check if private World of Warcraft servers were up or not. - **TCP** - should work with all servers
It's actually much more useful than that and can be used for most servers. - **UDP** - [Source RCON Protocol](https://developer.valvesoftware.com/wiki/Source_RCON_Protocol) is supported
It has been brought to my attention that this bot currently does not work for Ark servers.
### Note - updated for Felmyst server!
The config template contains IP/Ports for the new Felmyst game and logon servers
## Configuration ## Configuration
- Download the latest release [here](https://github.com/mgerb/ServerStatus/releases) - 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! - Execute the OS specific binary!
## Compiling from source ### Mentioning Roles/Users
- you must first get your role/user id (see below of obtaining ID's)
- for user `<@userid>`
- for role `<@&roleid>`
### Polling Interval
The polling interval is how often the bot will try to ping the servers.
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`
## With Docker
```
docker run -it -v /path/to/your/config.json:/server-status/config.json:ro mgerb/server-status
```
### Docker Compose
```
version: "2"
services:
server-status:
image: mgerb/server-status:latest
volumes:
- /path/to/your/config.json:/server-status/config.json
```
## Usage
To get the current status of your servers simply type `!ServerStatus` in chat.
![Server Status](https://i.imgur.com/ZzQSBJp.png)
## Compiling from source
- Make sure Go and Make are installed - Make sure Go and Make are installed
- make all - make all
@@ -26,19 +54,7 @@ The config template contains IP/Ports for the new Felmyst game and logon servers
https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token
### How to get your room ID ### 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. 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="https://camo.githubusercontent.com/9f759ec8b45a6e9dd2242bc64c82897c74f84a25/687474703a2f2f692e696d6775722e636f6d2f47684b70424d512e676966"/>
## List server status in discord channel
`!ServerStatus`
```
Elysium PvP is online!
Zethkur PvP is online!
Anathema PvP is online!
Darrowshire PvE is online!
Elysium Authentication Server is online!
```

View File

@@ -2,22 +2,34 @@ package serverstatus
import ( import (
"log" "log"
"strconv"
"strings"
"time" "time"
"github.com/anvie/port-scanner" "github.com/anvie/port-scanner"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/mgerb/serverstatus/bot" steam "github.com/kidoman/go-steam"
"github.com/mgerb/serverstatus/config" "github.com/mgerb/ServerStatus/bot"
"github.com/mgerb/ServerStatus/config"
) )
const (
red = 0xf4425c
green = 0x42f477
blue = 0x42adf4
)
// Start - start port scanner and bot listeners
func Start() { func Start() {
//set each server status as online to start //set each server status as online to start
for i, _ := range config.Config.Servers { for i := range config.Config.Servers {
config.Config.Servers[i].Online = true config.Config.Servers[i].Online = true
} }
err := bot.Session.UpdateStatus(0, config.Config.GameStatus) err := bot.Session.UpdateStatus(0, config.Config.GameStatus)
sendMessageToRooms(blue, "Server Status", "Bot started! Type !ServerStatus to see the status of your servers :smiley:", false)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
@@ -42,26 +54,54 @@ func scanServers() {
serverScanner := portscanner.NewPortScanner(server.Address, time.Second*2, 1) serverScanner := portscanner.NewPortScanner(server.Address, time.Second*2, 1)
serverUp := serverScanner.IsOpen(server.Port) //check if the port is open serverUp := serverScanner.IsOpen(server.Port) //check if the port is open
// 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 { if serverUp && serverUp != prevServerUp {
sendMessage(config.Config.RoleToNotify + " " + server.Name + " is now online!") sendMessageToRooms(green, server.Name, "Is now online :smiley:", true)
} else if !serverUp && serverUp != prevServerUp { } else if !serverUp && serverUp != prevServerUp {
sendMessage(config.Config.RoleToNotify + " " + server.Name + " went offline!") sendMessageToRooms(red, server.Name, "Has gone offline :frowning2:", true)
} }
config.Config.Servers[index].Online = serverUp config.Config.Servers[index].Online = serverUp
} }
time.Sleep(time.Second * 5) time.Sleep(time.Second * config.Config.PollingInterval)
} }
} }
func sendMessage(message string) { func sendMessageToRooms(color int, title, description string, mentionRoles bool) {
for _, roomID := range config.Config.RoomIDList { for _, roomID := range config.Config.RoomIDList {
bot.Session.ChannelMessageSend(roomID, message) if mentionRoles {
content := strings.Join(config.Config.RolesToNotify, " ")
bot.Session.ChannelMessageSend(roomID, content)
}
sendEmbededMessage(roomID, color, title, description)
} }
} }
// This function will be called every time a new func sendEmbededMessage(roomID string, color int, title, description string) {
embed := &discordgo.MessageEmbed{
Color: color,
Title: title,
Description: description,
}
bot.Session.ChannelMessageSendEmbed(roomID, embed)
}
// MessageHandler will be called every time a new
// message is created on any channel that the autenticated bot has access to. // message is created on any channel that the autenticated bot has access to.
func MessageHandler(s *discordgo.Session, m *discordgo.MessageCreate) { func MessageHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
@@ -73,9 +113,9 @@ func MessageHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
if m.Content == "!ServerStatus" { if m.Content == "!ServerStatus" {
for _, server := range config.Config.Servers { for _, server := range config.Config.Servers {
if server.Online { if server.Online {
s.ChannelMessageSend(m.ChannelID, server.Name+" is online!") sendEmbededMessage(m.ChannelID, green, server.Name, "Online!")
} else { } else {
s.ChannelMessageSend(m.ChannelID, server.Name+" is down!") sendEmbededMessage(m.ChannelID, red, server.Name, "Offline!")
} }
} }
} }