diff --git a/api/search.go b/api/search.go index 06a69a0..a19f601 100644 --- a/api/search.go +++ b/api/search.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" "strconv" + "time" meilisearch "github.com/felipemarinho97/torrent-indexer/search" ) @@ -13,6 +14,23 @@ type MeilisearchHandler struct { Module *meilisearch.SearchIndexer } +// HealthResponse represents the health check response +type HealthResponse struct { + Status string `json:"status"` + Service string `json:"service"` + Details map[string]interface{} `json:"details,omitempty"` + Timestamp string `json:"timestamp"` +} + +// StatsResponse represents the stats endpoint response +type StatsResponse struct { + Status string `json:"status"` + NumberOfDocuments int64 `json:"numberOfDocuments"` + IsIndexing bool `json:"isIndexing"` + FieldDistribution map[string]int64 `json:"fieldDistribution"` + Service string `json:"service"` +} + // NewMeilisearchHandler creates a new instance of MeilisearchHandler. func NewMeilisearchHandler(module *meilisearch.SearchIndexer) *MeilisearchHandler { return &MeilisearchHandler{Module: module} @@ -53,3 +71,88 @@ func (h *MeilisearchHandler) SearchTorrentHandler(w http.ResponseWriter, r *http http.Error(w, "Failed to encode response", http.StatusInternalServerError) } } + +// HealthHandler provides a health check endpoint for Meilisearch. +func (h *MeilisearchHandler) HealthHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + w.Header().Set("Content-Type", "application/json") + + // Check if Meilisearch is healthy + isHealthy := h.Module.IsHealthy() + + response := HealthResponse{ + Service: "meilisearch", + Timestamp: getCurrentTimestamp(), + } + + if isHealthy { + // Try to get additional stats for more detailed health info + stats, err := h.Module.GetStats() + if err == nil { + response.Status = "healthy" + response.Details = map[string]interface{}{ + "documents": stats.NumberOfDocuments, + "indexing": stats.IsIndexing, + } + w.WriteHeader(http.StatusOK) + } else { + // Service is up but can't get stats + response.Status = "degraded" + response.Details = map[string]interface{}{ + "error": "Could not retrieve stats", + } + w.WriteHeader(http.StatusOK) + } + } else { + // Service is down + response.Status = "unhealthy" + w.WriteHeader(http.StatusServiceUnavailable) + } + + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + } +} + +// StatsHandler provides detailed statistics about the Meilisearch index. +func (h *MeilisearchHandler) StatsHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + w.Header().Set("Content-Type", "application/json") + + // Get detailed stats from Meilisearch + stats, err := h.Module.GetStats() + if err != nil { + // Check if it's a connectivity issue + if !h.Module.IsHealthy() { + http.Error(w, "Meilisearch service is unavailable", http.StatusServiceUnavailable) + return + } + http.Error(w, "Failed to retrieve statistics", http.StatusInternalServerError) + return + } + + response := StatsResponse{ + Status: "healthy", + Service: "meilisearch", + NumberOfDocuments: stats.NumberOfDocuments, + IsIndexing: stats.IsIndexing, + FieldDistribution: stats.FieldDistribution, + } + + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + } +} + +// getCurrentTimestamp returns the current timestamp in RFC3339 format +func getCurrentTimestamp() string { + return time.Now().Format(time.RFC3339) +} diff --git a/main.go b/main.go index d31ee4e..00c2e87 100644 --- a/main.go +++ b/main.go @@ -54,6 +54,8 @@ func main() { indexerMux.HandleFunc("/indexers/torrent-dos-filmes", indexers.HandlerTorrentDosFilmesIndexer) indexerMux.HandleFunc("/indexers/manual", indexers.HandlerManualIndexer) indexerMux.HandleFunc("/search", search.SearchTorrentHandler) + indexerMux.HandleFunc("/search/health", search.HealthHandler) + indexerMux.HandleFunc("/search/stats", search.StatsHandler) indexerMux.Handle("/ui/", http.StripPrefix("/ui/", http.FileServer(http.FS(public.UIFiles)))) metricsMux.Handle("/metrics", promhttp.Handler()) diff --git a/public/index.html b/public/index.html index 102347d..999b879 100644 --- a/public/index.html +++ b/public/index.html @@ -9,8 +9,8 @@ -
-Search functionality may be disabled or experiencing issues. Please try again later.
+