Update for Minecraft

Using template from the PHP version of this site, from 2016/2017!

$ ls -Alh
-rw-r--r-- 1 chandler chandler 1.5K Jan  4  2017 index.php
master 1.0.0
Chandler Swift 2023-09-29 19:59:46 -05:00
parent 8dd1b7b58d
commit f17074d22d
Signed by: chandlerswift
GPG Key ID: A851D929D52FB93F
7 changed files with 93 additions and 110 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
factorio-site
minecraft-site
config.json

13
go.mod
View File

@ -1,8 +1,15 @@
module github.com/chandlerswift/factorio-site
module git.chandlerswift.com/chandlerswift/minecraft-site
go 1.14
go 1.21
require (
github.com/james4k/rcon v0.0.0-20120923215419-8fbb8268b60a
github.com/dreamscached/minequery/v2 v2.4.1
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
)
require (
github.com/google/uuid v1.3.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 // indirect
golang.org/x/text v0.3.7 // indirect
)

12
go.sum
View File

@ -1,5 +1,9 @@
github.com/james4k/rcon v0.0.0-20120923215419-8fbb8268b60a h1:JxcWget6X/VfBMKxPIc28Jel37LGREut2fpV+ObkwJ0=
github.com/james4k/rcon v0.0.0-20120923215419-8fbb8268b60a/go.mod h1:1qNVsDcmNQDsAXYfUuF/Z0rtK5eT8x9D6Pi7S3PjXAg=
github.com/dreamscached/minequery/v2 v2.4.1 h1:jRx0oQ80dq6+2a01oHiSm0s3KzLs3cT+9vkAL2tLOHc=
github.com/dreamscached/minequery/v2 v2.4.1/go.mod h1:wKoUWEntOrS1jnJJfq73nkkU8cjNCCQojUHqXAtibZU=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -7,5 +11,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2eP
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -5,63 +5,40 @@ import (
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"os"
"github.com/james4k/rcon"
"github.com/dreamscached/minequery/v2"
"golang.org/x/crypto/acme/autocert"
)
type config struct {
Title string `json:"title"`
Content string `json:"content"`
Servers []server `json:"servers"`
UseTLS bool `json:"useTLS"`
TLSHostname string `json:"tlshostname"`
ServerPort int `json:"serverport"`
BackupDir string `json:"backupDir"`
Title string `json:"title"`
Content template.HTML `json:"content"`
Servers []server `json:"servers"`
UseTLS bool `json:"useTLS"`
TLSHostname string `json:"tlshostname"`
ServerPort int `json:"serverport"`
BackupDir string `json:"backupDir"`
}
type server struct {
Host string `json:"host"` // for display only
Port int `json:"port"`
RCONHost string `json:"rconhost"` // not displayed, but used to connect; leave blank for no RCON connection
RCONPort int `json:"rconport"`
RCONPassword string `json:"rconpassword"`
Title string `json:"title"` // TODO: get this from RCON?
Description string `json:"description"` // TODO: get this from RCON?
Version string // Populated by RCON
Players string // Populated by RCON
rconConnection *rcon.RemoteConsole
Host string `json:"host"`
Port int `json:"port"`
Status *minequery.Status17
}
type pageData struct {
Title string
Content string
Content template.HTML
Servers []server
}
// 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
}
response, _, err = s.rconConnection.Read()
if err != nil {
return "", err
}
return
}
func main() {
// Parse config file
configData, err := ioutil.ReadFile("./config.json")
configData, err := os.ReadFile("./config.json")
if err != nil {
log.Fatalf("Error reading config file: %v\n", err)
}
@ -91,32 +68,14 @@ func main() {
log.Fatalf("Error parsing HTML template: %v\n", err)
}
// Connect to RCON servers
for i := range config.Servers {
s := config.Servers[i]
if s.RCONHost != "" {
config.Servers[i].rconConnection, err = rcon.Dial(fmt.Sprintf("%v:%v", s.RCONHost, s.RCONPort), s.RCONPassword)
if err != nil {
log.Fatalf("Error making RCON connection to %v: %v", s.Title, err)
}
defer config.Servers[i].rconConnection.Close()
}
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Update servers with current data
for i, s := range config.Servers {
if s.rconConnection != nil {
config.Servers[i].Players, err = s.rconCommand("/players o")
if err != nil {
log.Printf("Error executing players online command: %v\n", err)
}
config.Servers[i].Version, err = s.rconCommand("/version")
if err != nil {
log.Printf("Error executing version command: %v\n", err)
}
// TODO: Query instead (opportunistically?) to get mod lists, etc
config.Servers[i].Status, err = minequery.Ping17(s.Host, s.Port)
if err != nil {
log.Printf("Error querying server: %v", err)
}
}
@ -127,7 +86,7 @@ func main() {
})
// Serve backup directory
if serveBackups { // TODO: also remove HTML if disabled
if serveBackups { // TODO: add HTML
http.Handle("/backups/", http.StripPrefix("/backups/", http.FileServer(http.Dir(config.BackupDir))))
}

View File

@ -1,49 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.Title}}</title>
<style>
html {
font-family: sans-serif;
padding: 10px;
}
/* https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3 */
.light {
color: #888;
}
.light a {
color: #88f;
}
.light a:hover {
color: #00e;
}
.light a:visited {
color: #a9b;
}
.light a:visited:hover {
color: #518;
}
:not(:hover) .optional-port {
color: #ccc;
}
</style>
</head>
<body>
<h1>{{.Title}}</h1>
<p>{{.Content}}</p>
<p>Backups are taken and archived periodically, and made available in the <a href="/backups">backup archive</a>.</p>
{{range .Servers}}
<h3>{{.Title}}</h3>
<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>ChandlerSwift.com Minecraft</title>
<style>
body{margin:1em auto;max-width:40em;padding:0 .62em;font:1.2em sans-serif; line-height: 1.62em;}h1,h2,h3{line-height:1.2em;}@media print{body{max-width:none}}
/* https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3 */
.light {
color: #888;
}
.light a {
color: #88f;
}
.light a:hover {
color: #00e;
}
.light a:visited {
color: #a9b;
}
.light a:visited:hover {
color: #518;
}
:not(:hover) .optional-port {
color: #666;
}
</style>
<link rel="shortcut icon" href="https://chandlerswift.com/favicon.ico" />
</head>
<body>
<header>
<h1>{{.Title}}</h1>
<p>{{.Content}}</p>
</header>
{{range .Servers}}
<section>
<h2 style="margin-bottom: 0;"><code>{{.Host}}{{if eq .Port 25565}}<span class="optional-port">:{{.Port}}</span>{{else}}:{{.Port}}{{end}}</code></h2>
{{if .Status}}
<span style="color: #666; font-style: italic;">{{.Status.Description.String}}</span>
<ul>
<li>Minecraft Version: {{.Status.VersionName}}</li>
<li>Players Online: {{.Status.OnlinePlayers}}/{{.Status.MaxPlayers}}
{{if gt .Status.OnlinePlayers 0}}
<ul>
<li><b>Description:</b> {{.Description}}</li>
<li><b>Connection String:</b> {{.Host}}{{if eq .Port 34197}}<span class="optional-port">:{{.Port}}</span>{{else}}:{{.Port}}{{end}}</li>
{{if ne .RCONHost ""}}
<li><b>Version:</b> {{.Version}}</li>
<li><b>Current players:</b><br>{{.Players}}</li>
{{range $i, $player := .Status.SamplePlayers}}
<li>{{$player.Nickname}}</li>
{{end}}
</ul>
{{end}}
<p class="light">This page maintained by chandlerswift's <a href="https://github.com/chandlerswift/factorio-site">factorio server list</a>.</p>
</body>
{{end}}
</li>
</ul>
{{else}}
<span style="color: #666;">Unable to connect to server to check status</span>
{{end}}
</section>
{{end}}
<p class="light">This page maintained by chandlerswift's <a href="https://git.chandlerswift.com/chandlerswift/minecraft-site">minecraft server list</a>.</p>
</body>
</html>