package webserver import ( "encoding/json" "fmt" "net/http" serveractions "manage-servers/server-actions" "github.com/spf13/viper" ) type WebServer struct { servers []serveractions.Server } func StartWebServer(servers []serveractions.Server) { ws := &WebServer{servers: servers} fmt.Println("Starting web server on :8080...") http.HandleFunc("/", ws.handleRoot) http.HandleFunc("/servers", ws.handleServers) http.HandleFunc("/wake", ws.handleWakeServer) http.HandleFunc("/shutdown", ws.handleShutdownServer) http.HandleFunc("/reboot", ws.handleRebootServer) http.HandleFunc("/status", ws.handleStatus) http.HandleFunc("/find-mac", ws.handleFindMac) http.HandleFunc("/ssh", ws.handleSSH) if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Printf("Error starting server: %v\n", err) } } func (ws *WebServer) handleRoot(w http.ResponseWriter, r *http.Request) { serveractions.LogDebug("Handling root request: %s %s", r.Method, r.URL.Path) http.ServeFile(w, r, "index.html") } func (ws *WebServer) handleServers(w http.ResponseWriter, r *http.Request) { serveractions.LogDebug("Handling /servers request: %s", r.Method) switch r.Method { case http.MethodGet: ws.getServers(w, r) case http.MethodPost: ws.addServer(w, r) case http.MethodPut: ws.updateServer(w, r) case http.MethodDelete: ws.deleteServer(w, r) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func (ws *WebServer) getServers(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(ws.servers) } func (ws *WebServer) updateServer(w http.ResponseWriter, r *http.Request) { oldName := r.URL.Query().Get("oldName") if oldName == "" { http.Error(w, "Missing old server name", http.StatusBadRequest) return } var updatedServer serveractions.Server if err := json.NewDecoder(r.Body).Decode(&updatedServer); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } found := false for i, server := range ws.servers { if server.Name == oldName { ws.servers[i] = updatedServer found = true break } } if !found { http.Error(w, "Server not found", http.StatusNotFound) return } viper.Set("servers", ws.servers) if err := viper.WriteConfig(); err != nil { http.Error(w, fmt.Sprintf("Error writing config file: %v", err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (ws *WebServer) addServer(w http.ResponseWriter, r *http.Request) { var newServer serveractions.Server if err := json.NewDecoder(r.Body).Decode(&newServer); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } ws.servers = append(ws.servers, newServer) viper.Set("servers", ws.servers) if err := viper.WriteConfig(); err != nil { // If the file does not exist, create it if _, ok := err.(viper.ConfigFileNotFoundError); ok { if err = viper.SafeWriteConfig(); err != nil { http.Error(w, fmt.Sprintf("Error creating config file: %v", err), http.StatusInternalServerError) return } } else { http.Error(w, fmt.Sprintf("Error writing config file: %v", err), http.StatusInternalServerError) return } } w.WriteHeader(http.StatusCreated) } func (ws *WebServer) deleteServer(w http.ResponseWriter, r *http.Request) { serverName := r.URL.Query().Get("name") if serverName == "" { http.Error(w, "Missing server name", http.StatusBadRequest) return } var found bool var updatedServers []serveractions.Server for _, server := range ws.servers { if server.Name != serverName { updatedServers = append(updatedServers, server) } else { found = true } } if !found { http.Error(w, "Server not found", http.StatusNotFound) return } ws.servers = updatedServers viper.Set("servers", ws.servers) if err := viper.WriteConfig(); err != nil { http.Error(w, fmt.Sprintf("Error writing config file: %v", err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func (ws *WebServer) handleWakeServer(w http.ResponseWriter, r *http.Request) { serverName := r.URL.Query().Get("name") if serverName == "" { http.Error(w, "Missing server name", http.StatusBadRequest) return } serveractions.WakeServer(serverName, ws.servers) w.WriteHeader(http.StatusOK) } func (ws *WebServer) handleShutdownServer(w http.ResponseWriter, r *http.Request) { serverName := r.URL.Query().Get("name") if serverName == "" { http.Error(w, "Missing server name", http.StatusBadRequest) return } serveractions.ShutdownServer(serverName, ws.servers) w.WriteHeader(http.StatusOK) } func (ws *WebServer) handleRebootServer(w http.ResponseWriter, r *http.Request) { serverName := r.URL.Query().Get("name") if serverName == "" { http.Error(w, "Missing server name", http.StatusBadRequest) return } serveractions.RebootServer(serverName, ws.servers) w.WriteHeader(http.StatusOK) } func (ws *WebServer) handleStatus(w http.ResponseWriter, r *http.Request) { serverName := r.URL.Query().Get("name") serveractions.LogDebug("Checking status for server: %s", serverName) if serverName == "" { http.Error(w, "Missing server name", http.StatusBadRequest) return } for _, s := range ws.servers { if s.Name == serverName { online := serveractions.PingHost(s.IP) status := "Offline" if online { status = "Online" } w.Write([]byte(status)) return } } http.Error(w, "Server not found", http.StatusNotFound) } func (ws *WebServer) handleFindMac(w http.ResponseWriter, r *http.Request) { ip := r.URL.Query().Get("ip") user := r.URL.Query().Get("user") pass := r.URL.Query().Get("pass") serveractions.LogDebug("Handling /find-mac request for IP: %s (SSH provided: %v)", ip, user != "") if ip == "" { http.Error(w, "Missing IP address", http.StatusBadRequest) return } // Try ARP first mac, err := serveractions.GetMacAddress(ip) if err != nil { serveractions.LogDebug("ARP lookup failed for %s: %v. Trying SSH fallback...", ip, err) // Try SSH fallback if credentials are provided if user != "" && pass != "" { mac, err = serveractions.GetMacAddressSSH(ip, user, pass) if err != nil { serveractions.LogDebug("SSH lookup also failed for %s: %v", ip, err) http.Error(w, "MAC address not found via ARP or SSH", http.StatusNotFound) return } } else { serveractions.LogDebug("No SSH credentials for fallback for %s", ip) http.Error(w, "MAC address not found in local network. Please provide SSH credentials for remote lookup.", http.StatusNotFound) return } } w.Write([]byte(mac)) }