2020-03-19 23:20:59 -05:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-03-29 21:05:34 -05:00
|
|
|
"crypto/tls"
|
2020-03-29 22:02:18 -05:00
|
|
|
"encoding/json"
|
2020-03-19 23:20:59 -05:00
|
|
|
"fmt"
|
|
|
|
"html/template"
|
2020-03-29 22:02:18 -05:00
|
|
|
"io/ioutil"
|
2020-03-19 23:40:23 -05:00
|
|
|
"log"
|
2020-03-19 23:20:59 -05:00
|
|
|
"net/http"
|
2020-04-17 19:53:02 -05:00
|
|
|
"os"
|
2020-03-19 23:40:23 -05:00
|
|
|
|
|
|
|
"github.com/james4k/rcon"
|
2020-03-29 21:05:34 -05:00
|
|
|
"golang.org/x/crypto/acme/autocert"
|
2020-03-19 23:20:59 -05:00
|
|
|
)
|
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
type config struct {
|
2020-03-30 20:00:48 -05:00
|
|
|
UseTLS bool `json:"useTLS"`
|
|
|
|
Servers []server `json:"servers"`
|
|
|
|
TLSHostname string `json:"tlshostname"`
|
|
|
|
DebugServerPort int `json:"debugserverport"`
|
2020-04-17 19:53:02 -05:00
|
|
|
BackupDir string `json:"backupDir"`
|
2020-03-29 22:02:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
type server struct {
|
|
|
|
Host string `json:"host"`
|
|
|
|
Port int `json:"port"`
|
|
|
|
RCONPort int `json:"rconport"`
|
|
|
|
RCONPassword string `json:"rconpassword"`
|
|
|
|
Title string `json:"title"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
rconConnection *rcon.RemoteConsole
|
|
|
|
}
|
|
|
|
|
2020-03-19 23:20:59 -05:00
|
|
|
type serverData struct {
|
2020-03-29 22:02:18 -05:00
|
|
|
IPAddr string
|
|
|
|
Port int
|
|
|
|
Title string
|
|
|
|
Players string
|
|
|
|
Version string
|
|
|
|
Description string
|
2020-03-19 23:20:59 -05:00
|
|
|
}
|
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
// rconCommand executes a command on the server, and returns the server's
|
|
|
|
// response as a string.
|
|
|
|
func (s server) rconCommand(command string) (response string, err error) {
|
|
|
|
_, err = s.rconConnection.Write(command)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2020-03-19 23:20:59 -05:00
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
response, _, err = s.rconConnection.Read()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2020-03-19 23:20:59 -05:00
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
// Parse config file
|
|
|
|
configData, err := ioutil.ReadFile("./config.json")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error reading config file: %v\n", err)
|
2020-03-19 23:20:59 -05:00
|
|
|
}
|
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
var config config
|
|
|
|
|
|
|
|
err = json.Unmarshal(configData, &config)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error parsing config file: %v\n", err)
|
2020-03-19 23:40:23 -05:00
|
|
|
}
|
|
|
|
|
2020-04-17 19:53:02 -05:00
|
|
|
serveBackups := true
|
|
|
|
if stat, err := os.Stat(config.BackupDir); os.IsNotExist(err) || !stat.IsDir() {
|
|
|
|
log.Printf("Backup directory %v does not exist; not serving backups.", config.BackupDir)
|
|
|
|
serveBackups = false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up templates
|
2020-03-19 23:20:59 -05:00
|
|
|
fmt.Print("Parsing templates...\n")
|
|
|
|
t, err := template.ParseFiles("templates/index.html")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error parsing HTML template: %v\n", err)
|
|
|
|
}
|
|
|
|
|
2020-04-17 19:53:02 -05:00
|
|
|
// Connect to RCON servers
|
2020-03-29 22:18:59 -05:00
|
|
|
for i := range config.Servers {
|
2020-03-29 22:23:04 -05:00
|
|
|
s := config.Servers[i]
|
2020-03-29 22:18:59 -05:00
|
|
|
config.Servers[i].rconConnection, err = rcon.Dial(fmt.Sprintf("%v:%v", s.Host, s.RCONPort), s.RCONPassword)
|
2020-03-29 22:02:18 -05:00
|
|
|
if err != nil {
|
2020-03-29 22:09:57 -05:00
|
|
|
log.Fatalf("Error making RCON connection to %v: %v", s.Title, err)
|
2020-03-29 22:02:18 -05:00
|
|
|
}
|
2020-03-29 22:09:57 -05:00
|
|
|
defer s.rconConnection.Close()
|
2020-03-19 23:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
2020-03-19 23:40:23 -05:00
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
data := []serverData{}
|
2020-03-19 23:40:23 -05:00
|
|
|
|
2020-03-29 22:09:57 -05:00
|
|
|
for _, s := range config.Servers {
|
2020-03-19 23:40:23 -05:00
|
|
|
|
2020-03-29 22:09:57 -05:00
|
|
|
playersOnline, err := s.rconCommand("/players o")
|
2020-03-29 22:02:18 -05:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error executing players online command: %v\n", err)
|
|
|
|
}
|
2020-03-29 21:32:18 -05:00
|
|
|
|
2020-03-29 22:09:57 -05:00
|
|
|
version, err := s.rconCommand("/version")
|
2020-03-29 22:02:18 -05:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error executing version command: %v\n", err)
|
|
|
|
}
|
2020-03-29 21:32:18 -05:00
|
|
|
|
2020-03-29 22:02:18 -05:00
|
|
|
data = append(data, serverData{
|
2020-03-29 22:09:57 -05:00
|
|
|
s.Host,
|
|
|
|
s.Port,
|
|
|
|
s.Title,
|
2020-03-29 22:02:18 -05:00
|
|
|
playersOnline,
|
|
|
|
version,
|
2020-03-29 22:09:57 -05:00
|
|
|
s.Description,
|
2020-03-29 22:02:18 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
}
|
2020-03-19 23:40:23 -05:00
|
|
|
|
2020-03-19 23:20:59 -05:00
|
|
|
t.Execute(w, data)
|
|
|
|
})
|
|
|
|
|
2020-04-17 19:53:02 -05:00
|
|
|
// Serve backup directory
|
|
|
|
if serveBackups {
|
|
|
|
http.Handle("/backups/", http.StripPrefix("/backups/", http.FileServer(http.Dir(config.BackupDir))))
|
|
|
|
}
|
|
|
|
|
2020-03-29 22:23:27 -05:00
|
|
|
if config.UseTLS {
|
2020-03-29 21:05:34 -05:00
|
|
|
|
2020-03-29 22:23:27 -05:00
|
|
|
certManager := autocert.Manager{
|
|
|
|
Prompt: autocert.AcceptTOS,
|
2020-03-30 20:00:48 -05:00
|
|
|
HostPolicy: autocert.HostWhitelist(config.TLSHostname),
|
2020-03-29 22:23:27 -05:00
|
|
|
Cache: autocert.DirCache("certs"),
|
|
|
|
}
|
2020-03-29 21:05:34 -05:00
|
|
|
|
2020-03-29 22:23:27 -05:00
|
|
|
srv := &http.Server{
|
|
|
|
Addr: ":https",
|
|
|
|
TLSConfig: &tls.Config{
|
|
|
|
GetCertificate: certManager.GetCertificate,
|
|
|
|
},
|
|
|
|
}
|
2020-03-29 21:05:34 -05:00
|
|
|
|
2020-03-29 22:23:27 -05:00
|
|
|
go http.ListenAndServe(":http", certManager.HTTPHandler(nil)) // Handler for LetsEncrypt
|
|
|
|
|
|
|
|
fmt.Println("Serving...")
|
|
|
|
srv.ListenAndServeTLS("", "") // Key/cert come from srv.TLSConfig
|
|
|
|
|
|
|
|
} else { // Debug
|
|
|
|
fmt.Println("Serving...")
|
2020-03-30 20:00:48 -05:00
|
|
|
if config.DebugServerPort == 0 { // Value not set in JSON
|
|
|
|
config.DebugServerPort = 8080
|
|
|
|
}
|
|
|
|
http.ListenAndServe(fmt.Sprintf(":%v", config.DebugServerPort), nil) // TODO: pass as config value
|
2020-03-29 22:23:27 -05:00
|
|
|
}
|
2020-03-19 23:20:59 -05:00
|
|
|
|
|
|
|
}
|