package login import ( "encoding/json" "fmt" "net/http" "strconv" "time" ) // handleWebRoot handles the root web interface page func (s *Server) handleWebRoot(w http.ResponseWriter, r *http.Request) { if !s.authenticateWebRequest(w, r) { return } html := ` EQ2Go Login Server

EQ2Go Login Server Administration

Version: 1.0.0-dev

-
Connected Clients
-
World Servers
-
Uptime

API Endpoints

` w.Header().Set("Content-Type", "text/html") w.Write([]byte(html)) } // handleAPIStatus handles the status API endpoint func (s *Server) handleAPIStatus(w http.ResponseWriter, r *http.Request) { if !s.authenticateWebRequest(w, r) { return } status := map[string]interface{}{ "server_name": s.config.ServerName, "version": "1.0.0-dev", "running": s.IsRunning(), "uptime": s.formatUptime(s.GetUptime()), "clients": s.GetClientCount(), "worlds": s.GetWorldCount(), "timestamp": time.Now().Unix(), } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(status) } // handleAPIClients handles the clients API endpoint func (s *Server) handleAPIClients(w http.ResponseWriter, r *http.Request) { if !s.authenticateWebRequest(w, r) { return } clients := s.clientList.GetClients() clientInfo := make([]map[string]interface{}, len(clients)) for i, client := range clients { clientInfo[i] = map[string]interface{}{ "ip_address": client.GetIPAddress(), "account_id": client.GetAccountID(), "account_name": client.GetAccountName(), "state": client.GetState().String(), "connect_time": client.GetConnectTime().Unix(), "last_activity": client.GetLastActivity().Unix(), } } response := map[string]interface{}{ "total_clients": len(clients), "clients": clientInfo, "stats": s.clientList.GetStats(), } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } // handleAPIWorlds handles the worlds API endpoint func (s *Server) handleAPIWorlds(w http.ResponseWriter, r *http.Request) { if !s.authenticateWebRequest(w, r) { return } worlds := s.worldList.GetAllWorlds() worldInfo := make([]map[string]interface{}, len(worlds)) for i, world := range worlds { worldInfo[i] = map[string]interface{}{ "id": world.ID, "name": world.Name, "address": world.Address, "port": world.Port, "status": world.Status, "population": world.Population, "max_players": world.MaxPlayers, "population_pct": world.GetPopulationPercentage(), "population_level": world.GetPopulationLevel(), "locked": world.IsLocked(), "hidden": world.IsHidden(), "last_heartbeat": world.LastHeartbeat, "description": world.Description, } } response := map[string]interface{}{ "total_worlds": len(worlds), "worlds": worldInfo, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } // authenticateWebRequest performs basic authentication for web requests func (s *Server) authenticateWebRequest(w http.ResponseWriter, r *http.Request) bool { // Skip authentication if no credentials are configured if s.config.WebUser == "" || s.config.WebPassword == "" { return true } username, password, ok := r.BasicAuth() if !ok { w.Header().Set("WWW-Authenticate", `Basic realm="EQ2Go Login Server"`) w.WriteHeader(401) w.Write([]byte("Unauthorized")) return false } if username != s.config.WebUser || password != s.config.WebPassword { w.Header().Set("WWW-Authenticate", `Basic realm="EQ2Go Login Server"`) w.WriteHeader(401) w.Write([]byte("Unauthorized")) return false } return true } // formatUptime formats uptime duration into a readable string func (s *Server) formatUptime(duration time.Duration) string { if duration == 0 { return "Not running" } days := int(duration.Hours()) / 24 hours := int(duration.Hours()) % 24 minutes := int(duration.Minutes()) % 60 seconds := int(duration.Seconds()) % 60 if days > 0 { return fmt.Sprintf("%dd %dh %dm %ds", days, hours, minutes, seconds) } else if hours > 0 { return fmt.Sprintf("%dh %dm %ds", hours, minutes, seconds) } else if minutes > 0 { return fmt.Sprintf("%dm %ds", minutes, seconds) } else { return fmt.Sprintf("%ds", seconds) } } // handleKickClient handles kicking a client (admin endpoint) func (s *Server) handleKickClient(w http.ResponseWriter, r *http.Request) { if !s.authenticateWebRequest(w, r) { return } if r.Method != "POST" { w.WriteHeader(405) w.Write([]byte("Method not allowed")) return } accountIDStr := r.FormValue("account_id") reason := r.FormValue("reason") if reason == "" { reason = "Kicked by administrator" } accountID, err := strconv.ParseInt(accountIDStr, 10, 32) if err != nil { w.WriteHeader(400) w.Write([]byte("Invalid account ID")) return } success := s.clientList.DisconnectByAccountID(int32(accountID), reason) response := map[string]interface{}{ "success": success, "message": "Client disconnected", } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) }