159 lines
4.6 KiB
Go
159 lines
4.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
meilisearch "github.com/felipemarinho97/torrent-indexer/search"
|
|
)
|
|
|
|
// MeilisearchHandler handles HTTP requests for Meilisearch integration.
|
|
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}
|
|
}
|
|
|
|
// SearchTorrentHandler handles the searching of torrent items.
|
|
func (h *MeilisearchHandler) SearchTorrentHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
query := r.URL.Query().Get("q")
|
|
if query == "" {
|
|
http.Error(w, "Query parameter 'q' is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
limitStr := r.URL.Query().Get("limit")
|
|
limit := 10 // Default limit
|
|
if limitStr != "" {
|
|
var err error
|
|
limit, err = strconv.Atoi(limitStr)
|
|
if err != nil || limit <= 0 {
|
|
http.Error(w, "Invalid limit parameter", http.StatusBadRequest)
|
|
return
|
|
}
|
|
}
|
|
|
|
results, err := h.Module.SearchTorrent(query, limit)
|
|
if err != nil {
|
|
http.Error(w, "Failed to search torrents", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if err := json.NewEncoder(w).Encode(results); err != nil {
|
|
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)
|
|
}
|