Agent-Status und Inaktivitaets-Erkennung implementiert

- Status wird aus last_heartbeat berechnet (online/stale/offline/unknown)
- GET /agents und GET /agents/{id} liefern status Feld
- agent_events Tabelle fuer Event-Tracking (Migration automatisch)
- Inaktivitaets-Monitor als Goroutine (prueft alle 60s, schreibt Events bei Statuswechsel)
- WebSocket Connect/Disconnect Events werden automatisch geschrieben
- API-Endpoints: GET /agents/events und GET /agents/{id}/events (?limit=N&type=X)
- DB-Methoden: InsertAgentEvent, GetAgentEvents, GetAllAgentEvents, GetAgentStatus
- README aktualisiert (Status-Doku, Events API, Dateistruktur)
This commit is contained in:
cynfo3000
2026-02-28 13:13:13 +01:00
parent 5d7a3cbcc1
commit c72b791796
7 changed files with 337 additions and 3 deletions
+56 -1
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"log"
"net/http"
"strconv"
"strings"
"time"
@@ -28,7 +29,9 @@ func (h *Handler) SetupRoutes(mux *http.ServeMux, hub *ws.Hub) {
mux.HandleFunc("POST /api/v1/agent/register", h.registerAgent)
mux.HandleFunc("POST /api/v1/agent/heartbeat", h.heartbeat)
mux.HandleFunc("GET /api/v1/agents", h.listAgents)
mux.HandleFunc("GET /api/v1/agents/events", h.getAllAgentEvents)
mux.HandleFunc("GET /api/v1/agents/{id}", h.getAgent)
mux.HandleFunc("GET /api/v1/agents/{id}/events", h.getAgentEvents)
mux.HandleFunc("GET /api/v1/agents/{id}/system", h.getSystemData)
mux.HandleFunc("DELETE /api/v1/agents/{id}", h.deleteAgent)
@@ -151,7 +154,19 @@ func (h *Handler) listAgents(w http.ResponseWriter, r *http.Request) {
if agents == nil {
agents = []models.Agent{}
}
writeJSON(w, http.StatusOK, agents)
// Status fuer jeden Agent berechnen
var response []models.AgentResponse
for _, a := range agents {
response = append(response, models.AgentResponse{
Agent: a,
Status: models.CalculateAgentStatus(a.LastHeartbeat),
})
}
if response == nil {
response = []models.AgentResponse{}
}
writeJSON(w, http.StatusOK, response)
}
// GET /api/v1/agents/{id}
@@ -170,6 +185,7 @@ func (h *Handler) getAgent(w http.ResponseWriter, r *http.Request) {
result := map[string]interface{}{
"agent": agent,
"status": models.CalculateAgentStatus(agent.LastHeartbeat),
"system_data": sysData,
}
writeJSON(w, http.StatusOK, result)
@@ -207,3 +223,42 @@ func (h *Handler) deleteAgent(w http.ResponseWriter, r *http.Request) {
log.Printf("Agent geloescht: %s", id)
writeJSON(w, http.StatusOK, map[string]string{"message": "Agent geloescht"})
}
// GET /api/v1/agents/{id}/events
func (h *Handler) getAgentEvents(w http.ResponseWriter, r *http.Request) {
agentID := r.PathValue("id")
eventType := r.URL.Query().Get("type")
limit := 100
if l := r.URL.Query().Get("limit"); l != "" {
if n, err := strconv.Atoi(l); err == nil && n > 0 {
limit = n
}
}
events, err := h.db.GetAgentEvents(agentID, eventType, limit)
if err != nil {
log.Printf("Fehler beim Laden der Events: %v", err)
writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
return
}
writeJSON(w, http.StatusOK, events)
}
// GET /api/v1/agents/events
func (h *Handler) getAllAgentEvents(w http.ResponseWriter, r *http.Request) {
eventType := r.URL.Query().Get("type")
limit := 100
if l := r.URL.Query().Get("limit"); l != "" {
if n, err := strconv.Atoi(l); err == nil && n > 0 {
limit = n
}
}
events, err := h.db.GetAllAgentEvents(eventType, limit)
if err != nil {
log.Printf("Fehler beim Laden der Events: %v", err)
writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
return
}
writeJSON(w, http.StatusOK, events)
}