Files
urldb/handlers/meilisearch_handler.go
2025-08-20 15:03:14 +08:00

271 lines
7.0 KiB
Go

package handlers
import (
"net/http"
"strconv"
"github.com/ctwj/urldb/db/converter"
"github.com/ctwj/urldb/services"
"github.com/ctwj/urldb/utils"
"github.com/gin-gonic/gin"
)
// MeilisearchHandler Meilisearch处理器
type MeilisearchHandler struct {
meilisearchManager *services.MeilisearchManager
}
// NewMeilisearchHandler 创建Meilisearch处理器
func NewMeilisearchHandler(meilisearchManager *services.MeilisearchManager) *MeilisearchHandler {
return &MeilisearchHandler{
meilisearchManager: meilisearchManager,
}
}
// TestConnection 测试Meilisearch连接
func (h *MeilisearchHandler) TestConnection(c *gin.Context) {
var req struct {
Host string `json:"host"`
Port interface{} `json:"port"` // 支持字符串或数字
MasterKey string `json:"masterKey"`
IndexName string `json:"indexName"` // 可选字段
}
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, "请求参数错误", http.StatusBadRequest)
return
}
// 验证必要字段
if req.Host == "" {
ErrorResponse(c, "主机地址不能为空", http.StatusBadRequest)
return
}
// 转换port为字符串
var portStr string
switch v := req.Port.(type) {
case string:
portStr = v
case float64:
portStr = strconv.Itoa(int(v))
case int:
portStr = strconv.Itoa(v)
default:
portStr = "7700" // 默认端口
}
// 如果没有提供索引名称,使用默认值
indexName := req.IndexName
if indexName == "" {
indexName = "resources"
}
// 创建临时服务进行测试
service := services.NewMeilisearchService(req.Host, portStr, req.MasterKey, indexName, true)
if err := service.HealthCheck(); err != nil {
ErrorResponse(c, "连接测试失败: "+err.Error(), http.StatusBadRequest)
return
}
SuccessResponse(c, gin.H{"message": "连接测试成功"})
}
// GetStatus 获取Meilisearch状态
func (h *MeilisearchHandler) GetStatus(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"enabled": false,
"healthy": false,
"message": "Meilisearch未初始化",
})
return
}
status, err := h.meilisearchManager.GetStatusWithHealthCheck()
if err != nil {
ErrorResponse(c, "获取状态失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, status)
}
// GetUnsyncedCount 获取未同步资源数量
func (h *MeilisearchHandler) GetUnsyncedCount(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{"count": 0})
return
}
count, err := h.meilisearchManager.GetUnsyncedCount()
if err != nil {
ErrorResponse(c, "获取未同步数量失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"count": count})
}
// GetUnsyncedResources 获取未同步的资源
func (h *MeilisearchHandler) GetUnsyncedResources(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"resources": []interface{}{},
"total": 0,
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
resources, total, err := h.meilisearchManager.GetUnsyncedResources(page, pageSize)
if err != nil {
ErrorResponse(c, "获取未同步资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"resources": converter.ToResourceResponseList(resources),
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetSyncedResources 获取已同步的资源
func (h *MeilisearchHandler) GetSyncedResources(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"resources": []interface{}{},
"total": 0,
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
resources, total, err := h.meilisearchManager.GetSyncedResources(page, pageSize)
if err != nil {
ErrorResponse(c, "获取已同步资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"resources": converter.ToResourceResponseList(resources),
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetAllResources 获取所有资源
func (h *MeilisearchHandler) GetAllResources(c *gin.Context) {
if h.meilisearchManager == nil {
SuccessResponse(c, gin.H{
"resources": []interface{}{},
"total": 0,
})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
resources, total, err := h.meilisearchManager.GetAllResources(page, pageSize)
if err != nil {
ErrorResponse(c, "获取所有资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"resources": converter.ToResourceResponseList(resources),
"total": total,
"page": page,
"page_size": pageSize,
})
}
// SyncAllResources 同步所有资源
func (h *MeilisearchHandler) SyncAllResources(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
utils.Info("开始同步所有资源到Meilisearch...")
_, err := h.meilisearchManager.SyncAllResources()
if err != nil {
ErrorResponse(c, "同步失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"message": "同步已开始,请查看进度",
})
}
// GetSyncProgress 获取同步进度
func (h *MeilisearchHandler) GetSyncProgress(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
progress := h.meilisearchManager.GetSyncProgress()
SuccessResponse(c, progress)
}
// StopSync 停止同步
func (h *MeilisearchHandler) StopSync(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
h.meilisearchManager.StopSync()
SuccessResponse(c, gin.H{
"message": "同步已停止",
})
}
// ClearIndex 清空索引
func (h *MeilisearchHandler) ClearIndex(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
if err := h.meilisearchManager.ClearIndex(); err != nil {
ErrorResponse(c, "清空索引失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"message": "清空索引成功"})
}
// UpdateIndexSettings 更新索引设置
func (h *MeilisearchHandler) UpdateIndexSettings(c *gin.Context) {
if h.meilisearchManager == nil {
ErrorResponse(c, "Meilisearch未初始化", http.StatusInternalServerError)
return
}
service := h.meilisearchManager.GetService()
if service == nil {
ErrorResponse(c, "Meilisearch服务未初始化", http.StatusInternalServerError)
return
}
if err := service.UpdateIndexSettings(); err != nil {
ErrorResponse(c, "更新索引设置失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"message": "索引设置更新成功"})
}