mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-05 23:26:38 +08:00
refactor(service): adopt feature-based architecture and rename pkg/diskcache
- Moved GORM/Redis CAPTCHA manager from internal/service/cap directly into the cohesive CAPTCHA app folder at internal/apps/cap/. - Moved background system cleanup handler from internal/service/cleanup.go into internal/apps/upload/cleanup.go. - Completely removed the global internal/service directory to keep module logic self-contained. - Renamed the core utility engine pkg/diskcache to pkg/cache/disk to separate underlying utility code from db/config integrations. - Renamed DiskCache struct in pkg/cache/disk to Cache to resolve revive package-name stuttering warning. - Regenerated Swagger API documentation and confirmed all tests compile and pass with 0 linter issues.
This commit is contained in:
@@ -17,7 +17,6 @@ import ("bytes"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/upload"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/user"
|
||||
"github.com/Rain-kl/Wavelet/internal/model"
|
||||
"github.com/Rain-kl/Wavelet/internal/service"
|
||||
"github.com/Rain-kl/Wavelet/internal/task"
|
||||
"github.com/Rain-kl/Wavelet/internal/testhelper"
|
||||
"github.com/Rain-kl/Wavelet/internal/util"
|
||||
@@ -92,7 +91,7 @@ func TestListTaskTypes(t *testing.T) {
|
||||
foundCleanup := false
|
||||
foundWarmImageCache := false
|
||||
for _, m := range taskMetas {
|
||||
if m.Type == service.TaskTypeSystemCleanup {
|
||||
if m.Type == upload.TaskTypeSystemCleanup {
|
||||
foundCleanup = true
|
||||
}
|
||||
if m.Type == upload.TaskTypeWarmImageCache {
|
||||
@@ -100,7 +99,7 @@ func TestListTaskTypes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
if !foundCleanup {
|
||||
t.Errorf("expected task type %s to be listed", service.TaskTypeSystemCleanup)
|
||||
t.Errorf("expected task type %s to be listed", upload.TaskTypeSystemCleanup)
|
||||
}
|
||||
if !foundWarmImageCache {
|
||||
t.Errorf("expected task type %s to be listed", upload.TaskTypeWarmImageCache)
|
||||
@@ -116,7 +115,7 @@ func TestDispatchTask(t *testing.T) {
|
||||
|
||||
t.Run("dispatch valid task successfully", func(t *testing.T) {
|
||||
payload := DispatchTaskRequest{
|
||||
TaskType: service.TaskTypeSystemCleanup,
|
||||
TaskType: upload.TaskTypeSystemCleanup,
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
req, _ := http.NewRequest("POST", "/api/v1/admin/tasks/dispatch", bytes.NewBuffer(body))
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
|
||||
package cap
|
||||
|
||||
import ("net/http"
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
caputil "github.com/Rain-kl/Wavelet/internal/service/cap"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/common/response")
|
||||
"github.com/Rain-kl/Wavelet/internal/common/response"
|
||||
)
|
||||
|
||||
// VerifyMiddleware returns a Gin middleware that checks and consumes the X-Cap-Token header.
|
||||
// enabledFunc is an optional callback allowing dynamic check of whether captcha protection is turned on.
|
||||
func VerifyMiddleware(mgr *caputil.Manager, scope string, enabledFunc func() bool) gin.HandlerFunc {
|
||||
func VerifyMiddleware(mgr *Manager, scope string, enabledFunc func() bool) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if enabledFunc != nil && !enabledFunc() {
|
||||
c.Next()
|
||||
|
||||
@@ -6,8 +6,7 @@ package cap
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
capService "github.com/Rain-kl/Wavelet/internal/service/cap"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type challengeRequest struct {
|
||||
@@ -28,7 +27,7 @@ type redeemRequest struct {
|
||||
// @Produce json
|
||||
// @Param request body challengeRequest false "可选范围限制参数"
|
||||
// @Success 200 {object} cap.ChallengeResponse "成功返回 PoW 难题"
|
||||
// @Failure 500 {object} capService.RedeemResponse "内部服务错误"
|
||||
// @Failure 500 {object} RedeemResponse "内部服务错误"
|
||||
// @Router /api/cap/challenge [post]
|
||||
func Challenge(c *gin.Context) {
|
||||
var req challengeRequest
|
||||
@@ -38,10 +37,10 @@ func Challenge(c *gin.Context) {
|
||||
req.Scope = "login"
|
||||
}
|
||||
|
||||
mgr := capService.GetDefaultManager()
|
||||
mgr := GetDefaultManager()
|
||||
resp, err := mgr.Generate(c.Request.Context(), req.Scope)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, capService.RedeemResponse{
|
||||
c.JSON(http.StatusInternalServerError, RedeemResponse{
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
@@ -58,14 +57,14 @@ func Challenge(c *gin.Context) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body redeemRequest true "难题 Token 与解答 solutions 数组"
|
||||
// @Success 200 {object} capService.RedeemResponse "核销成功,返回 X-Cap-Token"
|
||||
// @Failure 400 {object} capService.RedeemResponse "参数错误或核销失败"
|
||||
// @Failure 500 {object} capService.RedeemResponse "内部服务错误"
|
||||
// @Success 200 {object} RedeemResponse "核销成功,返回 X-Cap-Token"
|
||||
// @Failure 400 {object} RedeemResponse "参数错误或核销失败"
|
||||
// @Failure 500 {object} RedeemResponse "内部服务错误"
|
||||
// @Router /api/cap/redeem [post]
|
||||
func Redeem(c *gin.Context) {
|
||||
var req redeemRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, capService.RedeemResponse{
|
||||
c.JSON(http.StatusBadRequest, RedeemResponse{
|
||||
Success: false,
|
||||
Error: "无效的参数",
|
||||
})
|
||||
@@ -76,10 +75,10 @@ func Redeem(c *gin.Context) {
|
||||
req.Scope = "login"
|
||||
}
|
||||
|
||||
mgr := capService.GetDefaultManager()
|
||||
mgr := GetDefaultManager()
|
||||
resp, err := mgr.Redeem(c.Request.Context(), req.Token, req.Solutions, req.Scope)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, capService.RedeemResponse{
|
||||
c.JSON(http.StatusInternalServerError, RedeemResponse{
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
|
||||
@@ -13,8 +13,7 @@ import ("bytes"
|
||||
"github.com/Rain-kl/Wavelet/internal/db"
|
||||
"github.com/Rain-kl/Wavelet/internal/model"
|
||||
"github.com/Rain-kl/Wavelet/internal/testhelper"
|
||||
capUtil "github.com/Rain-kl/Wavelet/internal/service/cap"
|
||||
pkgcap "github.com/Rain-kl/Wavelet/pkg/cap"
|
||||
pkgcap "github.com/Rain-kl/Wavelet/pkg/cap"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/common/response")
|
||||
@@ -34,7 +33,7 @@ func TestCapEndpointsAndMiddleware(t *testing.T) {
|
||||
}
|
||||
|
||||
// Login endpoint with CAPTCHA middleware
|
||||
r.POST("/api/v1/user/login", VerifyMiddleware(capUtil.GetDefaultManager(), "login", func() bool {
|
||||
r.POST("/api/v1/user/login", VerifyMiddleware(GetDefaultManager(), "login", func() bool {
|
||||
enabled, err := model.GetBoolByKey(context.Background(), model.ConfigKeyCapLoginEnabled)
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -106,7 +105,7 @@ func TestCapEndpointsAndMiddleware(t *testing.T) {
|
||||
t.Fatalf("expected 200 OK for redeem, got %d. Body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var redeemResp capUtil.RedeemResponse
|
||||
var redeemResp RedeemResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &redeemResp); err != nil {
|
||||
t.Fatalf("failed to unmarshal redeem response: %v", err)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package service implements Wavelet's core background service processes.
|
||||
package service
|
||||
// Package upload implements upload tasks and file cleanup services.
|
||||
package upload
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/Rain-kl/Wavelet/internal/db"
|
||||
"github.com/Rain-kl/Wavelet/internal/diskcache"
|
||||
"github.com/Rain-kl/Wavelet/internal/model"
|
||||
"github.com/Rain-kl/Wavelet/internal/service"
|
||||
"github.com/Rain-kl/Wavelet/internal/storage"
|
||||
"github.com/Rain-kl/Wavelet/internal/task"
|
||||
"github.com/Rain-kl/Wavelet/internal/testhelper"
|
||||
@@ -111,7 +110,7 @@ func TestSystemCleanupHandler_Execute(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// 执行 handler
|
||||
handler := &service.SystemCleanupHandler{}
|
||||
handler := &SystemCleanupHandler{}
|
||||
result, err := handler.Execute(ctx, nil)
|
||||
|
||||
// 验证结果
|
||||
@@ -162,7 +161,7 @@ func TestSystemCleanupHandler_ExecuteNoFiles(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// 没有任何上传记录
|
||||
handler := &service.SystemCleanupHandler{}
|
||||
handler := &SystemCleanupHandler{}
|
||||
result, err := handler.Execute(ctx, nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
@@ -172,7 +171,7 @@ func TestSystemCleanupHandler_ExecuteNoFiles(t *testing.T) {
|
||||
|
||||
func TestSystemCleanupHandler_ImplementsTaskHandler(t *testing.T) {
|
||||
// 编译期验证 SystemCleanupHandler 实现了 TaskHandler 接口
|
||||
var _ task.TaskHandler = (*service.SystemCleanupHandler)(nil)
|
||||
var _ task.TaskHandler = (*SystemCleanupHandler)(nil)
|
||||
}
|
||||
|
||||
func TestWarmImageCacheHandlerValidatePayload(t *testing.T) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/db"
|
||||
"github.com/Rain-kl/Wavelet/internal/model"
|
||||
pkgcache "github.com/Rain-kl/Wavelet/pkg/diskcache"
|
||||
pkgcache "github.com/Rain-kl/Wavelet/pkg/cache/disk"
|
||||
)
|
||||
|
||||
// Status represents the runtime cache statistics.
|
||||
@@ -35,7 +35,7 @@ var ErrCacheMiss = pkgcache.ErrCacheMiss
|
||||
|
||||
// DiskCache is a wrapper around the generic pkg/diskcache that integrates with the DB for configs.
|
||||
type DiskCache struct {
|
||||
*pkgcache.DiskCache
|
||||
*pkgcache.Cache
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/upload"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/user"
|
||||
"github.com/Rain-kl/Wavelet/internal/model"
|
||||
capUtil "github.com/Rain-kl/Wavelet/internal/service/cap"
|
||||
|
||||
// Swagger 文档生成
|
||||
_ "github.com/Rain-kl/Wavelet/docs"
|
||||
@@ -208,21 +207,21 @@ func registerOAuthRoutes(apiV1Router *gin.RouterGroup) {
|
||||
func registerUserRoutes(apiV1Router *gin.RouterGroup) {
|
||||
userRouter := apiV1Router.Group("/user")
|
||||
{
|
||||
userRouter.POST("/login", capApp.VerifyMiddleware(capUtil.GetDefaultManager(), "login", func() bool {
|
||||
userRouter.POST("/login", capApp.VerifyMiddleware(capApp.GetDefaultManager(), "login", func() bool {
|
||||
enabled, err := model.GetBoolByKey(context.Background(), model.ConfigKeyCapLoginEnabled)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return enabled
|
||||
}), user.Login)
|
||||
userRouter.POST("/register", capApp.VerifyMiddleware(capUtil.GetDefaultManager(), "register", func() bool {
|
||||
userRouter.POST("/register", capApp.VerifyMiddleware(capApp.GetDefaultManager(), "register", func() bool {
|
||||
enabled, err := model.GetBoolByKey(context.Background(), model.ConfigKeyCapLoginEnabled)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return enabled
|
||||
}), user.Register)
|
||||
userRouter.POST("/send-email-code", capApp.VerifyMiddleware(capUtil.GetDefaultManager(), "send_email_code", func() bool {
|
||||
userRouter.POST("/send-email-code", capApp.VerifyMiddleware(capApp.GetDefaultManager(), "send_email_code", func() bool {
|
||||
enabled, err := model.GetBoolByKey(context.Background(), model.ConfigKeyCapLoginEnabled)
|
||||
if err != nil {
|
||||
return false
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/admin/push"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/upload"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/user"
|
||||
"github.com/Rain-kl/Wavelet/internal/service"
|
||||
"github.com/Rain-kl/Wavelet/internal/task"
|
||||
)
|
||||
|
||||
@@ -19,8 +18,8 @@ func Register() {
|
||||
task.RegisterTaskMeta(upload.StorageMigrationMeta)
|
||||
|
||||
// system cleanup
|
||||
task.RegisterHandler(service.SystemCleanupTask, &service.SystemCleanupHandler{})
|
||||
task.RegisterTaskMeta(service.SystemCleanupMeta)
|
||||
task.RegisterHandler(upload.SystemCleanupTask, &upload.SystemCleanupHandler{})
|
||||
task.RegisterTaskMeta(upload.SystemCleanupMeta)
|
||||
|
||||
// upload
|
||||
task.RegisterHandler(upload.WarmImageCacheTask, &upload.WarmImageCacheHandler{})
|
||||
|
||||
Reference in New Issue
Block a user