144 lines
3.6 KiB
Go
144 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// WebServer provides HTTP endpoints for monitoring
|
|
type WebServer struct {
|
|
config WebServerConfig
|
|
loginServer *LoginServer
|
|
server *http.Server
|
|
}
|
|
|
|
// NewWebServer creates a new web monitoring server
|
|
func NewWebServer(config WebServerConfig, loginServer *LoginServer) (*WebServer, error) {
|
|
ws := &WebServer{
|
|
config: config,
|
|
loginServer: loginServer,
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/status", ws.handleStatus)
|
|
mux.HandleFunc("/worlds", ws.handleWorlds)
|
|
mux.HandleFunc("/stats", ws.handleStats)
|
|
mux.HandleFunc("/health", ws.handleHealth)
|
|
|
|
ws.server = &http.Server{
|
|
Addr: fmt.Sprintf("%s:%d", config.Address, config.Port),
|
|
Handler: ws.basicAuth(mux),
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
}
|
|
|
|
return ws, nil
|
|
}
|
|
|
|
// Start begins the web server
|
|
func (ws *WebServer) Start() {
|
|
log.Printf("Starting web server on %s", ws.server.Addr)
|
|
|
|
var err error
|
|
if ws.config.CertFile != "" && ws.config.KeyFile != "" {
|
|
err = ws.server.ListenAndServeTLS(ws.config.CertFile, ws.config.KeyFile)
|
|
} else {
|
|
err = ws.server.ListenAndServe()
|
|
}
|
|
|
|
if err != http.ErrServerClosed {
|
|
log.Printf("Web server error: %v", err)
|
|
}
|
|
}
|
|
|
|
// Stop shuts down the web server
|
|
func (ws *WebServer) Stop() {
|
|
if ws.server != nil {
|
|
ws.server.Close()
|
|
}
|
|
}
|
|
|
|
// basicAuth provides basic HTTP authentication
|
|
func (ws *WebServer) basicAuth(next http.Handler) http.Handler {
|
|
if ws.config.Username == "" {
|
|
return next
|
|
}
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
username, password, ok := r.BasicAuth()
|
|
if !ok || username != ws.config.Username || password != ws.config.Password {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="Login Server"`)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte("Unauthorized"))
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// handleStatus returns server status information
|
|
func (ws *WebServer) handleStatus(w http.ResponseWriter, r *http.Request) {
|
|
stats := ws.loginServer.GetStats()
|
|
|
|
status := map[string]any{
|
|
"service": "eq2emu-login-server",
|
|
"version": "1.0.0",
|
|
"status": "running",
|
|
"timestamp": time.Now().UTC(),
|
|
"statistics": stats,
|
|
}
|
|
|
|
ws.writeJSON(w, status)
|
|
}
|
|
|
|
// handleWorlds returns world server information
|
|
func (ws *WebServer) handleWorlds(w http.ResponseWriter, r *http.Request) {
|
|
worlds := ws.loginServer.worldList.GetActiveWorlds()
|
|
worldStats := ws.loginServer.worldList.GetStats()
|
|
|
|
response := map[string]any{
|
|
"world_servers": worlds,
|
|
"statistics": worldStats,
|
|
}
|
|
|
|
ws.writeJSON(w, response)
|
|
}
|
|
|
|
// handleStats returns detailed server statistics
|
|
func (ws *WebServer) handleStats(w http.ResponseWriter, r *http.Request) {
|
|
serverStats := ws.loginServer.GetStats()
|
|
worldStats := ws.loginServer.worldList.GetStats()
|
|
|
|
stats := map[string]any{
|
|
"server": serverStats,
|
|
"worlds": worldStats,
|
|
"timestamp": time.Now().UTC(),
|
|
}
|
|
|
|
ws.writeJSON(w, stats)
|
|
}
|
|
|
|
// handleHealth returns basic health check
|
|
func (ws *WebServer) handleHealth(w http.ResponseWriter, r *http.Request) {
|
|
health := map[string]any{
|
|
"status": "healthy",
|
|
"timestamp": time.Now().UTC(),
|
|
}
|
|
|
|
ws.writeJSON(w, health)
|
|
}
|
|
|
|
// writeJSON writes JSON response with proper headers
|
|
func (ws *WebServer) writeJSON(w http.ResponseWriter, data any) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Header().Set("Cache-Control", "no-cache")
|
|
|
|
if err := json.NewEncoder(w).Encode(data); err != nil {
|
|
log.Printf("JSON encoding error: %v", err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
}
|
|
}
|