mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
Merge branch 'main' of https://github.com/ctwj/urldb into feat_xunlei
This commit is contained in:
@@ -2,11 +2,18 @@ package handlers
|
||||
|
||||
import (
|
||||
"github.com/ctwj/urldb/db/repo"
|
||||
"github.com/ctwj/urldb/services"
|
||||
)
|
||||
|
||||
var repoManager *repo.RepositoryManager
|
||||
var meilisearchManager *services.MeilisearchManager
|
||||
|
||||
// SetRepositoryManager 设置Repository管理器
|
||||
func SetRepositoryManager(rm *repo.RepositoryManager) {
|
||||
repoManager = rm
|
||||
func SetRepositoryManager(manager *repo.RepositoryManager) {
|
||||
repoManager = manager
|
||||
}
|
||||
|
||||
// SetMeilisearchManager 设置Meilisearch管理器
|
||||
func SetMeilisearchManager(manager *services.MeilisearchManager) {
|
||||
meilisearchManager = manager
|
||||
}
|
||||
|
||||
270
handlers/meilisearch_handler.go
Normal file
270
handlers/meilisearch_handler.go
Normal file
@@ -0,0 +1,270 @@
|
||||
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": "索引设置更新成功"})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/ctwj/urldb/db/dto"
|
||||
"github.com/ctwj/urldb/db/entity"
|
||||
|
||||
"github.com/ctwj/urldb/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -182,6 +183,7 @@ func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
|
||||
keyword := c.Query("keyword")
|
||||
tag := c.Query("tag")
|
||||
category := c.Query("category")
|
||||
panID := c.Query("pan_id")
|
||||
pageStr := c.DefaultQuery("page", "1")
|
||||
pageSizeStr := c.DefaultQuery("page_size", "20")
|
||||
|
||||
@@ -195,67 +197,129 @@ func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
// 构建搜索条件
|
||||
params := map[string]interface{}{
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
var resources []entity.Resource
|
||||
var total int64
|
||||
|
||||
// 如果启用了Meilisearch,优先使用Meilisearch搜索
|
||||
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
|
||||
// 构建过滤器
|
||||
filters := make(map[string]interface{})
|
||||
if category != "" {
|
||||
filters["category"] = category
|
||||
}
|
||||
if tag != "" {
|
||||
filters["tags"] = tag
|
||||
}
|
||||
if panID != "" {
|
||||
if id, err := strconv.ParseUint(panID, 10, 32); err == nil {
|
||||
// 根据pan_id获取pan_name
|
||||
pan, err := repoManager.PanRepository.FindByID(uint(id))
|
||||
if err == nil && pan != nil {
|
||||
filters["pan_name"] = pan.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用Meilisearch搜索
|
||||
service := meilisearchManager.GetService()
|
||||
if service != nil {
|
||||
docs, docTotal, err := service.Search(keyword, filters, page, pageSize)
|
||||
if err == nil {
|
||||
// 将Meilisearch文档转换为Resource实体(保持兼容性)
|
||||
for _, doc := range docs {
|
||||
resource := entity.Resource{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
Description: doc.Description,
|
||||
URL: doc.URL,
|
||||
SaveURL: doc.SaveURL,
|
||||
FileSize: doc.FileSize,
|
||||
Key: doc.Key,
|
||||
PanID: doc.PanID,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
total = docTotal
|
||||
} else {
|
||||
utils.Error("Meilisearch搜索失败,回退到数据库搜索: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if keyword != "" {
|
||||
params["search"] = keyword
|
||||
// 如果Meilisearch未启用或搜索失败,使用数据库搜索
|
||||
if meilisearchManager == nil || !meilisearchManager.IsEnabled() || err != nil {
|
||||
// 构建搜索条件
|
||||
params := map[string]interface{}{
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
}
|
||||
|
||||
if keyword != "" {
|
||||
params["search"] = keyword
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
params["tag"] = tag
|
||||
}
|
||||
|
||||
if category != "" {
|
||||
params["category"] = category
|
||||
}
|
||||
if panID != "" {
|
||||
if id, err := strconv.ParseUint(panID, 10, 32); err == nil {
|
||||
params["pan_id"] = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
// 执行数据库搜索
|
||||
resources, total, err = repoManager.ResourceRepository.SearchWithFilters(params)
|
||||
if err != nil {
|
||||
ErrorResponse(c, "搜索失败: "+err.Error(), 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
params["tag"] = tag
|
||||
}
|
||||
|
||||
if category != "" {
|
||||
params["category"] = category
|
||||
}
|
||||
|
||||
// 执行搜索
|
||||
resources, total, err := repoManager.ResourceRepository.SearchWithFilters(params)
|
||||
// 获取违禁词配置(只获取一次)
|
||||
cleanWords, err := utils.GetForbiddenWordsFromConfig(func() (string, error) {
|
||||
return repoManager.SystemConfigRepository.GetConfigValue(entity.ConfigKeyForbiddenWords)
|
||||
})
|
||||
if err != nil {
|
||||
ErrorResponse(c, "搜索失败: "+err.Error(), 500)
|
||||
return
|
||||
utils.Error("获取违禁词配置失败: %v", err)
|
||||
cleanWords = []string{} // 如果获取失败,使用空列表
|
||||
}
|
||||
|
||||
// 过滤违禁词
|
||||
filteredResources, foundForbiddenWords := h.filterForbiddenWords(resources)
|
||||
|
||||
// 计算过滤后的总数
|
||||
filteredTotal := len(filteredResources)
|
||||
|
||||
// 转换为响应格式
|
||||
// 转换为响应格式并添加违禁词标记
|
||||
var resourceResponses []gin.H
|
||||
for _, resource := range filteredResources {
|
||||
resourceResponses = append(resourceResponses, gin.H{
|
||||
"id": resource.ID,
|
||||
"title": resource.Title,
|
||||
"url": resource.URL,
|
||||
"description": resource.Description,
|
||||
"view_count": resource.ViewCount,
|
||||
"created_at": resource.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"updated_at": resource.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
for i, processedResource := range resources {
|
||||
originalResource := resources[i]
|
||||
forbiddenInfo := utils.CheckResourceForbiddenWords(originalResource.Title, originalResource.Description, cleanWords)
|
||||
|
||||
resourceResponse := gin.H{
|
||||
"id": processedResource.ID,
|
||||
"title": forbiddenInfo.ProcessedTitle, // 使用处理后的标题
|
||||
"url": processedResource.URL,
|
||||
"description": forbiddenInfo.ProcessedDesc, // 使用处理后的描述
|
||||
"view_count": processedResource.ViewCount,
|
||||
"created_at": processedResource.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"updated_at": processedResource.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
// 添加违禁词标记
|
||||
resourceResponse["has_forbidden_words"] = forbiddenInfo.HasForbiddenWords
|
||||
resourceResponse["forbidden_words"] = forbiddenInfo.ForbiddenWords
|
||||
resourceResponses = append(resourceResponses, resourceResponse)
|
||||
}
|
||||
|
||||
// 构建响应数据
|
||||
responseData := gin.H{
|
||||
"list": resourceResponses,
|
||||
"total": filteredTotal,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"limit": pageSize,
|
||||
}
|
||||
|
||||
// 如果存在违禁词过滤,添加提醒字段
|
||||
if len(foundForbiddenWords) > 0 {
|
||||
responseData["forbidden_words_filtered"] = true
|
||||
responseData["filtered_forbidden_words"] = foundForbiddenWords
|
||||
responseData["original_total"] = total
|
||||
responseData["filtered_count"] = total - int64(filteredTotal)
|
||||
}
|
||||
|
||||
SuccessResponse(c, responseData)
|
||||
}
|
||||
|
||||
|
||||
@@ -64,19 +64,123 @@ func GetResources(c *gin.Context) {
|
||||
params["pan_name"] = panName
|
||||
}
|
||||
|
||||
resources, total, err := repoManager.ResourceRepository.SearchWithFilters(params)
|
||||
// 获取违禁词配置(只获取一次)
|
||||
cleanWords, err := utils.GetForbiddenWordsFromConfig(func() (string, error) {
|
||||
return repoManager.SystemConfigRepository.GetConfigValue(entity.ConfigKeyForbiddenWords)
|
||||
})
|
||||
if err != nil {
|
||||
utils.Error("获取违禁词配置失败: %v", err)
|
||||
cleanWords = []string{} // 如果获取失败,使用空列表
|
||||
}
|
||||
|
||||
var resources []entity.Resource
|
||||
var total int64
|
||||
|
||||
// 如果有搜索关键词且启用了Meilisearch,优先使用Meilisearch搜索
|
||||
if search := c.Query("search"); search != "" && meilisearchManager != nil && meilisearchManager.IsEnabled() {
|
||||
// 构建Meilisearch过滤器
|
||||
filters := make(map[string]interface{})
|
||||
if panID := c.Query("pan_id"); panID != "" {
|
||||
if id, err := strconv.ParseUint(panID, 10, 32); err == nil {
|
||||
// 直接使用pan_id进行过滤
|
||||
filters["pan_id"] = id
|
||||
}
|
||||
}
|
||||
|
||||
// 使用Meilisearch搜索
|
||||
service := meilisearchManager.GetService()
|
||||
if service != nil {
|
||||
docs, docTotal, err := service.Search(search, filters, page, pageSize)
|
||||
if err == nil {
|
||||
|
||||
// 将Meilisearch文档转换为ResourceResponse(包含高亮信息)并处理违禁词
|
||||
var resourceResponses []dto.ResourceResponse
|
||||
for _, doc := range docs {
|
||||
resourceResponse := converter.ToResourceResponseFromMeilisearch(doc)
|
||||
|
||||
// 处理违禁词(Meilisearch场景,需要处理高亮标记)
|
||||
if len(cleanWords) > 0 {
|
||||
forbiddenInfo := utils.CheckResourceForbiddenWords(resourceResponse.Title, resourceResponse.Description, cleanWords)
|
||||
if forbiddenInfo.HasForbiddenWords {
|
||||
resourceResponse.Title = forbiddenInfo.ProcessedTitle
|
||||
resourceResponse.Description = forbiddenInfo.ProcessedDesc
|
||||
resourceResponse.TitleHighlight = forbiddenInfo.ProcessedTitle
|
||||
resourceResponse.DescriptionHighlight = forbiddenInfo.ProcessedDesc
|
||||
}
|
||||
resourceResponse.HasForbiddenWords = forbiddenInfo.HasForbiddenWords
|
||||
resourceResponse.ForbiddenWords = forbiddenInfo.ForbiddenWords
|
||||
}
|
||||
|
||||
resourceResponses = append(resourceResponses, resourceResponse)
|
||||
}
|
||||
|
||||
// 返回Meilisearch搜索结果(包含高亮信息)
|
||||
SuccessResponse(c, gin.H{
|
||||
"data": resourceResponses,
|
||||
"total": docTotal,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
"source": "meilisearch",
|
||||
})
|
||||
return
|
||||
} else {
|
||||
utils.Error("Meilisearch搜索失败,回退到数据库搜索: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果Meilisearch未启用、搜索失败或没有搜索关键词,使用数据库搜索
|
||||
if meilisearchManager == nil || !meilisearchManager.IsEnabled() || len(resources) == 0 {
|
||||
resources, total, err = repoManager.ResourceRepository.SearchWithFilters(params)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"data": converter.ToResourceResponseList(resources),
|
||||
// 处理违禁词替换和标记
|
||||
var processedResources []entity.Resource
|
||||
if len(cleanWords) > 0 {
|
||||
processedResources = utils.ProcessResourcesForbiddenWords(resources, cleanWords)
|
||||
} else {
|
||||
processedResources = resources
|
||||
}
|
||||
|
||||
// 转换为响应格式并添加违禁词标记
|
||||
var resourceResponses []gin.H
|
||||
for i, processedResource := range processedResources {
|
||||
// 使用原始资源进行检查违禁词(数据库搜索场景,使用普通处理)
|
||||
originalResource := resources[i]
|
||||
forbiddenInfo := utils.CheckResourceForbiddenWords(originalResource.Title, originalResource.Description, cleanWords)
|
||||
|
||||
resourceResponse := gin.H{
|
||||
"id": processedResource.ID,
|
||||
"title": forbiddenInfo.ProcessedTitle, // 使用处理后的标题
|
||||
"url": processedResource.URL,
|
||||
"description": forbiddenInfo.ProcessedDesc, // 使用处理后的描述
|
||||
"pan_id": processedResource.PanID,
|
||||
"view_count": processedResource.ViewCount,
|
||||
"created_at": processedResource.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"updated_at": processedResource.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
// 添加违禁词标记
|
||||
resourceResponse["has_forbidden_words"] = forbiddenInfo.HasForbiddenWords
|
||||
resourceResponse["forbidden_words"] = forbiddenInfo.ForbiddenWords
|
||||
|
||||
resourceResponses = append(resourceResponses, resourceResponse)
|
||||
}
|
||||
|
||||
// 构建响应数据
|
||||
responseData := gin.H{
|
||||
"data": resourceResponses,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
})
|
||||
}
|
||||
|
||||
SuccessResponse(c, responseData)
|
||||
}
|
||||
|
||||
// GetResourceByID 根据ID获取资源
|
||||
@@ -164,6 +268,15 @@ func CreateResource(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 同步到Meilisearch
|
||||
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
|
||||
go func() {
|
||||
if err := meilisearchManager.SyncResourceToMeilisearch(resource); err != nil {
|
||||
utils.Error("同步资源到Meilisearch失败: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"message": "资源创建成功",
|
||||
"resource": converter.ToResourceResponse(resource),
|
||||
@@ -240,6 +353,15 @@ func UpdateResource(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 同步到Meilisearch
|
||||
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
|
||||
go func() {
|
||||
if err := meilisearchManager.SyncResourceToMeilisearch(resource); err != nil {
|
||||
utils.Error("同步资源到Meilisearch失败: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
SuccessResponse(c, gin.H{"message": "资源更新成功"})
|
||||
}
|
||||
|
||||
@@ -271,12 +393,53 @@ func SearchResources(c *gin.Context) {
|
||||
var total int64
|
||||
var err error
|
||||
|
||||
if query == "" {
|
||||
// 搜索关键词为空时,返回最新记录(分页)
|
||||
resources, total, err = repoManager.ResourceRepository.FindWithRelationsPaginated(page, pageSize)
|
||||
} else {
|
||||
// 有搜索关键词时,执行搜索
|
||||
resources, total, err = repoManager.ResourceRepository.Search(query, nil, page, pageSize)
|
||||
// 如果启用了Meilisearch,优先使用Meilisearch搜索
|
||||
if meilisearchManager != nil && meilisearchManager.IsEnabled() {
|
||||
// 构建过滤器
|
||||
filters := make(map[string]interface{})
|
||||
if categoryID := c.Query("category_id"); categoryID != "" {
|
||||
if id, err := strconv.ParseUint(categoryID, 10, 32); err == nil {
|
||||
filters["category"] = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用Meilisearch搜索
|
||||
service := meilisearchManager.GetService()
|
||||
if service != nil {
|
||||
docs, docTotal, err := service.Search(query, filters, page, pageSize)
|
||||
if err == nil {
|
||||
// 将Meilisearch文档转换为Resource实体
|
||||
for _, doc := range docs {
|
||||
resource := entity.Resource{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
Description: doc.Description,
|
||||
URL: doc.URL,
|
||||
SaveURL: doc.SaveURL,
|
||||
FileSize: doc.FileSize,
|
||||
Key: doc.Key,
|
||||
PanID: doc.PanID,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
total = docTotal
|
||||
} else {
|
||||
utils.Error("Meilisearch搜索失败,回退到数据库搜索: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果Meilisearch未启用或搜索失败,使用数据库搜索
|
||||
if meilisearchManager == nil || !meilisearchManager.IsEnabled() || err != nil {
|
||||
if query == "" {
|
||||
// 搜索关键词为空时,返回最新记录(分页)
|
||||
resources, total, err = repoManager.ResourceRepository.FindWithRelationsPaginated(page, pageSize)
|
||||
} else {
|
||||
// 有搜索关键词时,执行搜索
|
||||
resources, total, err = repoManager.ResourceRepository.Search(query, nil, page, pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -195,6 +195,17 @@ func UpdateSystemConfig(c *gin.Context) {
|
||||
// 刷新系统配置缓存
|
||||
pan.RefreshSystemConfigCache()
|
||||
|
||||
// 重新加载Meilisearch配置(如果Meilisearch配置有变更)
|
||||
if req.MeilisearchEnabled != nil || req.MeilisearchHost != nil || req.MeilisearchPort != nil || req.MeilisearchMasterKey != nil || req.MeilisearchIndexName != nil {
|
||||
if meilisearchManager != nil {
|
||||
if err := meilisearchManager.ReloadConfig(); err != nil {
|
||||
utils.Error("重新加载Meilisearch配置失败: %v", err)
|
||||
} else {
|
||||
utils.Debug("Meilisearch配置重新加载成功")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据配置更新定时任务状态(错误不影响配置保存)
|
||||
scheduler := scheduler.GetGlobalScheduler(
|
||||
repoManager.HotDramaRepository,
|
||||
@@ -311,6 +322,12 @@ func ToggleAutoProcess(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 确保配置缓存已刷新
|
||||
if err := repoManager.SystemConfigRepository.SafeRefreshConfigCache(); err != nil {
|
||||
utils.Error("刷新配置缓存失败: %v", err)
|
||||
// 不返回错误,因为配置已经保存成功
|
||||
}
|
||||
|
||||
// 更新定时任务状态
|
||||
scheduler := scheduler.GetGlobalScheduler(
|
||||
repoManager.HotDramaRepository,
|
||||
|
||||
@@ -50,7 +50,7 @@ func (h *TaskHandler) CreateBatchTransferTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Info("创建批量转存任务: %s,资源数量: %d,选择账号数量: %d", req.Title, len(req.Resources), len(req.SelectedAccounts))
|
||||
utils.Debug("创建批量转存任务: %s,资源数量: %d,选择账号数量: %d", req.Title, len(req.Resources), len(req.SelectedAccounts))
|
||||
|
||||
// 构建任务配置
|
||||
taskConfig := map[string]interface{}{
|
||||
@@ -105,7 +105,7 @@ func (h *TaskHandler) CreateBatchTransferTask(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
utils.Info("批量转存任务创建完成: %d, 共 %d 项", newTask.ID, len(req.Resources))
|
||||
utils.Debug("批量转存任务创建完成: %d, 共 %d 项", newTask.ID, len(req.Resources))
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"task_id": newTask.ID,
|
||||
@@ -123,8 +123,6 @@ func (h *TaskHandler) StartTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Info("启动任务: %d", taskID)
|
||||
|
||||
err = h.taskManager.StartTask(uint(taskID))
|
||||
if err != nil {
|
||||
utils.Error("启动任务失败: %v", err)
|
||||
@@ -132,6 +130,8 @@ func (h *TaskHandler) StartTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Debug("启动任务: %d", taskID)
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"message": "任务启动成功",
|
||||
})
|
||||
@@ -146,8 +146,6 @@ func (h *TaskHandler) StopTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Info("停止任务: %d", taskID)
|
||||
|
||||
err = h.taskManager.StopTask(uint(taskID))
|
||||
if err != nil {
|
||||
utils.Error("停止任务失败: %v", err)
|
||||
@@ -155,6 +153,8 @@ func (h *TaskHandler) StopTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Debug("停止任务: %d", taskID)
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"message": "任务停止成功",
|
||||
})
|
||||
@@ -169,8 +169,6 @@ func (h *TaskHandler) PauseTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Info("暂停任务: %d", taskID)
|
||||
|
||||
err = h.taskManager.PauseTask(uint(taskID))
|
||||
if err != nil {
|
||||
utils.Error("暂停任务失败: %v", err)
|
||||
@@ -178,6 +176,8 @@ func (h *TaskHandler) PauseTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Debug("暂停任务: %d", taskID)
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"message": "任务暂停成功",
|
||||
})
|
||||
@@ -234,13 +234,25 @@ func (h *TaskHandler) GetTaskStatus(c *gin.Context) {
|
||||
|
||||
// GetTasks 获取任务列表
|
||||
func (h *TaskHandler) GetTasks(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
|
||||
taskType := c.Query("task_type")
|
||||
// 获取查询参数
|
||||
pageStr := c.DefaultQuery("page", "1")
|
||||
pageSizeStr := c.DefaultQuery("pageSize", "10")
|
||||
taskType := c.Query("taskType")
|
||||
status := c.Query("status")
|
||||
|
||||
utils.Info("GetTasks: 获取任务列表 page=%d, pageSize=%d, taskType=%s, status=%s", page, pageSize, taskType, status)
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
pageSize, err := strconv.Atoi(pageSizeStr)
|
||||
if err != nil || pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
utils.Debug("GetTasks: 获取任务列表 page=%d, pageSize=%d, taskType=%s, status=%s", page, pageSize, taskType, status)
|
||||
|
||||
// 获取任务列表
|
||||
tasks, total, err := h.repoMgr.TaskRepository.GetList(page, pageSize, taskType, status)
|
||||
if err != nil {
|
||||
utils.Error("获取任务列表失败: %v", err)
|
||||
@@ -248,19 +260,19 @@ func (h *TaskHandler) GetTasks(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Info("GetTasks: 从数据库获取到 %d 个任务", len(tasks))
|
||||
utils.Debug("GetTasks: 从数据库获取到 %d 个任务", len(tasks))
|
||||
|
||||
// 为每个任务添加运行状态
|
||||
var result []gin.H
|
||||
// 获取任务运行状态
|
||||
var taskList []gin.H
|
||||
for _, task := range tasks {
|
||||
isRunning := h.taskManager.IsTaskRunning(task.ID)
|
||||
utils.Info("GetTasks: 任务 %d (%s) 数据库状态: %s, TaskManager运行状态: %v", task.ID, task.Title, task.Status, isRunning)
|
||||
utils.Debug("GetTasks: 任务 %d (%s) 数据库状态: %s, TaskManager运行状态: %v", task.ID, task.Title, task.Status, isRunning)
|
||||
|
||||
result = append(result, gin.H{
|
||||
taskList = append(taskList, gin.H{
|
||||
"id": task.ID,
|
||||
"title": task.Title,
|
||||
"description": task.Description,
|
||||
"task_type": task.Type,
|
||||
"type": task.Type,
|
||||
"status": task.Status,
|
||||
"total_items": task.TotalItems,
|
||||
"processed_items": task.ProcessedItems,
|
||||
@@ -273,10 +285,11 @@ func (h *TaskHandler) GetTasks(c *gin.Context) {
|
||||
}
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"items": result,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"size": pageSize,
|
||||
"tasks": taskList,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
"total_pages": (total + int64(pageSize) - 1) / int64(pageSize),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -348,7 +361,7 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
|
||||
|
||||
// 检查任务是否在运行
|
||||
if h.taskManager.IsTaskRunning(uint(taskID)) {
|
||||
ErrorResponse(c, "任务正在运行,请先停止任务", http.StatusBadRequest)
|
||||
ErrorResponse(c, "任务正在运行中,无法删除", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -368,7 +381,8 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Info("任务删除成功: %d", taskID)
|
||||
utils.Debug("任务删除成功: %d", taskID)
|
||||
|
||||
SuccessResponse(c, gin.H{
|
||||
"message": "任务删除成功",
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user