chore(lint): unify formatting on golangci-lint fmt (gofumpt), uncap issue reporting, fix gofumpt drift

- make format 现在与 code-check 使用同一格式化器(golangci-lint fmt),消除 goimports -local 与 gofumpt 的格式拉锯
- .golangci.yml 关闭默认 50/3 截断,完整上报所有问题(只增强不弱化)
- 全库 gofumpt 规范化(203 files, 纯格式无行为变更)
This commit is contained in:
ryan
2026-08-28 16:31:53 +08:00
parent 078ad9b2f3
commit 528240026d
204 changed files with 572 additions and 718 deletions
+1
View File
@@ -0,0 +1 @@
{"ts":"2026-08-28T00:00:00Z","iter":0,"type":"baseline","metrics":{"lint_issues":45,"dup_issues":15,"tests_passed":44},"description":"baseline: 45 golangci issues (15 dupl), all tests pass","asi":{"note":"quick wins queue: gofumpt(4)+revive(8); then goconst/mnd; gosec; nilerr bug; contextcheck; dupl batches; nestif"}}
+7
View File
@@ -37,6 +37,7 @@ linters:
dupl: dupl:
threshold: 80 threshold: 80
cyclop: cyclop:
max-complexity: 20 max-complexity: 20
package-average: 10 package-average: 10
@@ -54,6 +55,12 @@ linters:
- condition - condition
- return - return
# 完整上报所有问题(取消 golangci 默认 50/3 截断,保证 code-check 与度量真实)
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters: formatters:
enable: enable:
- gofumpt - gofumpt
+2 -3
View File
@@ -14,9 +14,8 @@ license-check:
scripts/update_go_license.sh --check scripts/update_go_license.sh --check
format: format:
@echo "==> Formatting backend Go source with goimports..." @echo "==> Formatting backend Go source with golangci-lint fmt (gofumpt, same gate as code-check)..."
@command -v goimports >/dev/null 2>&1 || { echo 'error: goimports is required. Run: go install golang.org/x/tools/cmd/goimports@latest' >&2; exit 1; } cd backend && golangci-lint fmt
goimports -w -local $(MODULE) $$(find backend -type f -name '*.go' -not -path './.git/*')
@echo "==> Formatting frontend source..." @echo "==> Formatting frontend source..."
cd frontend && pnpm format cd frontend && pnpm format
+1 -2
View File
@@ -5,11 +5,10 @@
package cmd package cmd
import ( import (
"Wavelet/core"
"log" "log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"Wavelet/core"
) )
var allCmd = &cobra.Command{ var allCmd = &cobra.Command{
+1 -2
View File
@@ -4,11 +4,10 @@
package cmd package cmd
import ( import (
"Wavelet/core"
"log" "log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"Wavelet/core"
) )
var apiCmd = &cobra.Command{ var apiCmd = &cobra.Command{
+12 -12
View File
@@ -4,17 +4,6 @@
package cmd package cmd
import ( import (
"context"
"database/sql"
"fmt"
"io/fs"
"log"
"path/filepath"
"time"
"github.com/pressly/goose/v3"
goosedb "github.com/pressly/goose/v3/database"
"Wavelet/core" "Wavelet/core"
"Wavelet/core/contracts" "Wavelet/core/contracts"
"Wavelet/pkg/config" "Wavelet/pkg/config"
@@ -33,9 +22,20 @@ import (
"Wavelet/plugins/drivers/driver_inproc_worker" "Wavelet/plugins/drivers/driver_inproc_worker"
"Wavelet/plugins/infra/cache" "Wavelet/plugins/infra/cache"
"Wavelet/plugins/infra/cache_memory" "Wavelet/plugins/infra/cache_memory"
infradb "Wavelet/plugins/infra/database"
"Wavelet/plugins/infra/logger" "Wavelet/plugins/infra/logger"
"Wavelet/plugins/infra/storage" "Wavelet/plugins/infra/storage"
"context"
"database/sql"
"fmt"
"io/fs"
"log"
"path/filepath"
"time"
"github.com/pressly/goose/v3"
goosedb "github.com/pressly/goose/v3/database"
infradb "Wavelet/plugins/infra/database"
) )
// newWaveletApp creates a core.App wired with Wavelet platform infrastructure, domain plugins, and profile drivers. // newWaveletApp creates a core.App wired with Wavelet platform infrastructure, domain plugins, and profile drivers.
+2 -3
View File
@@ -4,13 +4,12 @@
package cmd package cmd
import ( import (
"Wavelet/core"
"Wavelet/pkg/config"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
"Wavelet/pkg/config"
) )
func TestNewWaveletAppProfiles(t *testing.T) { func TestNewWaveletAppProfiles(t *testing.T) {
+2 -3
View File
@@ -7,12 +7,11 @@
package cmd package cmd
import ( import (
"Wavelet/pkg/buildinfo"
"Wavelet/pkg/config"
"fmt" "fmt"
"runtime" "runtime"
"strings" "strings"
"Wavelet/pkg/buildinfo"
"Wavelet/pkg/config"
) )
//nolint:unused // startup banner formatting utilities //nolint:unused // startup banner formatting utilities
+2 -3
View File
@@ -4,11 +4,10 @@
package cmd package cmd
import ( import (
"strings"
"testing"
"Wavelet/pkg/buildinfo" "Wavelet/pkg/buildinfo"
"Wavelet/pkg/config" "Wavelet/pkg/config"
"strings"
"testing"
) )
func TestFormatStartupBanner(t *testing.T) { func TestFormatStartupBanner(t *testing.T) {
+4 -5
View File
@@ -4,6 +4,10 @@
package cmd package cmd
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
"Wavelet/pkg/config"
"context" "context"
"fmt" "fmt"
"sync/atomic" "sync/atomic"
@@ -12,11 +16,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
"Wavelet/pkg/config"
) )
func TestRedisPluggability_Simulation(t *testing.T) { func TestRedisPluggability_Simulation(t *testing.T) {
+2 -3
View File
@@ -4,6 +4,8 @@
package cmd package cmd
import ( import (
"Wavelet/plugins/domain/auth"
"Wavelet/plugins/infra/database"
"bufio" "bufio"
"context" "context"
"crypto/rand" "crypto/rand"
@@ -14,12 +16,9 @@ import (
"strings" "strings"
userdomain "Wavelet/plugins/domain/user" userdomain "Wavelet/plugins/domain/user"
"Wavelet/plugins/infra/database"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/plugins/domain/auth"
) )
var ( var (
+1 -1
View File
@@ -4,13 +4,13 @@
package cmd package cmd
import ( import (
"Wavelet/pkg/testhelper"
"bytes" "bytes"
"io" "io"
"os" "os"
"testing" "testing"
"time" "time"
"Wavelet/pkg/testhelper"
userdomain "Wavelet/plugins/domain/user" userdomain "Wavelet/plugins/domain/user"
) )
+4 -5
View File
@@ -4,16 +4,15 @@
package cmd package cmd
import ( import (
"Wavelet/pkg/buildinfo"
"Wavelet/pkg/config"
"Wavelet/pkg/logger"
"Wavelet/pkg/trace"
"context" "context"
"log" "log"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"Wavelet/pkg/buildinfo"
"Wavelet/pkg/config"
"Wavelet/pkg/logger"
"Wavelet/pkg/trace"
) )
const traceShutdownTimeout = 10 * time.Second const traceShutdownTimeout = 10 * time.Second
+1 -2
View File
@@ -4,11 +4,10 @@
package cmd package cmd
import ( import (
"Wavelet/core"
"log" "log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"Wavelet/core"
) )
var schedulerCmd = &cobra.Command{ var schedulerCmd = &cobra.Command{
+1 -2
View File
@@ -4,11 +4,10 @@
package cmd package cmd
import ( import (
"Wavelet/core"
"log" "log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"Wavelet/core"
) )
var workerCmd = &cobra.Command{ var workerCmd = &cobra.Command{
+2 -3
View File
@@ -4,6 +4,8 @@
package core_test package core_test
import ( import (
"Wavelet/core"
"Wavelet/core/extpoints"
"context" "context"
"errors" "errors"
"sync" "sync"
@@ -13,9 +15,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
"Wavelet/core/extpoints"
) )
// appMockDriver is a test driver tracking its start/stop lifecycle. // appMockDriver is a test driver tracking its start/stop lifecycle.
+2 -3
View File
@@ -4,13 +4,12 @@
package core package core
import ( import (
"Wavelet/core/extpoints"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"time" "time"
"Wavelet/core/extpoints"
) )
// Context is the central micro-kernel service bus and runtime lifecycle container. // Context is the central micro-kernel service bus and runtime lifecycle container.
@@ -103,7 +102,7 @@ func (c *Context) GoContext() context.Context {
} }
// Set stores an arbitrary key-value pair in this Context's local storage. // Set stores an arbitrary key-value pair in this Context's local storage.
func (c *Context) Set(key any, val any) { func (c *Context) Set(key, val any) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
if c.values == nil { if c.values == nil {
+1 -2
View File
@@ -4,6 +4,7 @@
package core_test package core_test
import ( import (
"Wavelet/core"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@@ -14,8 +15,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
) )
// Sample services for testing // Sample services for testing
+1 -1
View File
@@ -68,6 +68,6 @@ type TaskService interface {
ValidatePayload(taskType string, payload []byte) ([]byte, error) ValidatePayload(taskType string, payload []byte) ([]byte, error)
ReloadScheduler() error ReloadScheduler() error
AppendLog(ctx context.Context, format string, args ...any) AppendLog(ctx context.Context, format string, args ...any)
ListExecutions(ctx context.Context, taskType string, status string, page, pageSize int) ([]TaskExecutionDTO, int64, error) ListExecutions(ctx context.Context, taskType, status string, page, pageSize int) ([]TaskExecutionDTO, int64, error)
GetExecution(ctx context.Context, id uint64) (*TaskExecutionDTO, error) GetExecution(ctx context.Context, id uint64) (*TaskExecutionDTO, error)
} }
+4 -3
View File
@@ -14,8 +14,10 @@ import (
const maxHandlerParams = 2 const maxHandlerParams = 2
var ctxInterfaceType = reflect.TypeFor[context.Context]() var (
var errInterfaceType = reflect.TypeFor[error]() ctxInterfaceType = reflect.TypeFor[context.Context]()
errInterfaceType = reflect.TypeFor[error]()
)
type eventListener struct { type eventListener struct {
id uint64 id uint64
@@ -213,7 +215,6 @@ func (b *EventBus) Emit(ctx context.Context, topic string, payload any) error {
} }
return resErr return resErr
}() }()
if err != nil { if err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
+1 -2
View File
@@ -4,6 +4,7 @@
package core_test package core_test
import ( import (
"Wavelet/core"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@@ -13,8 +14,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
) )
type UserRegisteredEvent struct { type UserRegisteredEvent struct {
+2 -3
View File
@@ -4,6 +4,8 @@
package extpoints_test package extpoints_test
import ( import (
"Wavelet/core"
"Wavelet/core/extpoints"
"context" "context"
"testing" "testing"
"testing/fstest" "testing/fstest"
@@ -11,9 +13,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
"Wavelet/core/extpoints"
) )
func TestRouterExtension(t *testing.T) { func TestRouterExtension(t *testing.T) {
+1 -1
View File
@@ -21,7 +21,7 @@ type RouteDefinition struct {
type RouterExtension interface { type RouterExtension interface {
Use(middlewares ...any) Use(middlewares ...any)
Group(prefix string, middlewares ...any) RouterExtension Group(prefix string, middlewares ...any) RouterExtension
Handle(method string, path string, handlers ...any) RouteDefinition Handle(method, path string, handlers ...any) RouteDefinition
GET(path string, handlers ...any) RouteDefinition GET(path string, handlers ...any) RouteDefinition
POST(path string, handlers ...any) RouteDefinition POST(path string, handlers ...any) RouteDefinition
PUT(path string, handlers ...any) RouteDefinition PUT(path string, handlers ...any) RouteDefinition
+4 -4
View File
@@ -28,8 +28,8 @@ func WithScheduleOption(key string, val any) ScheduleOption {
// ScheduleExtension defines the interface for registering and querying cron/scheduled tasks. // ScheduleExtension defines the interface for registering and querying cron/scheduled tasks.
type ScheduleExtension interface { type ScheduleExtension interface {
Register(spec string, taskType string, payload any, opts ...ScheduleOption) Register(spec, taskType string, payload any, opts ...ScheduleOption)
RegisterCron(spec string, taskType string, payload any, opts ...ScheduleOption) RegisterCron(spec, taskType string, payload any, opts ...ScheduleOption)
Schedules() []ScheduleDefinition Schedules() []ScheduleDefinition
Get(taskType string) (ScheduleDefinition, bool) Get(taskType string) (ScheduleDefinition, bool)
Unregister(taskType string) bool Unregister(taskType string) bool
@@ -50,7 +50,7 @@ func NewScheduleRegistry() *ScheduleRegistry {
} }
// Register adds a schedule definition. // Register adds a schedule definition.
func (s *ScheduleRegistry) Register(spec string, taskType string, payload any, opts ...ScheduleOption) { func (s *ScheduleRegistry) Register(spec, taskType string, payload any, opts ...ScheduleOption) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
@@ -82,7 +82,7 @@ func (s *ScheduleRegistry) Register(spec string, taskType string, payload any, o
} }
// RegisterCron is an alias for Register. // RegisterCron is an alias for Register.
func (s *ScheduleRegistry) RegisterCron(spec string, taskType string, payload any, opts ...ScheduleOption) { func (s *ScheduleRegistry) RegisterCron(spec, taskType string, payload any, opts ...ScheduleOption) {
s.Register(spec, taskType, payload, opts...) s.Register(spec, taskType, payload, opts...)
} }
+1 -2
View File
@@ -4,14 +4,13 @@
package core_test package core_test
import ( import (
"Wavelet/core"
"context" "context"
"reflect" "reflect"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
) )
type MockServiceA interface { type MockServiceA interface {
+3 -3
View File
@@ -30,7 +30,7 @@ func (s *scopedRouterExtension) Group(prefix string, middlewares ...any) extpoin
return newScopedRouterExtension(s.ctx, subGroup) return newScopedRouterExtension(s.ctx, subGroup)
} }
func (s *scopedRouterExtension) Handle(method string, path string, handlers ...any) extpoints.RouteDefinition { func (s *scopedRouterExtension) Handle(method, path string, handlers ...any) extpoints.RouteDefinition {
rd := s.underlying.Handle(method, path, handlers...) rd := s.underlying.Handle(method, path, handlers...)
routeID := rd.ID routeID := rd.ID
s.ctx.OnDispose(func() error { s.ctx.OnDispose(func() error {
@@ -141,7 +141,7 @@ func newScopedScheduleExtension(ctx *Context, underlying extpoints.ScheduleExten
} }
} }
func (s *scopedScheduleExtension) Register(spec string, taskType string, payload any, opts ...extpoints.ScheduleOption) { func (s *scopedScheduleExtension) Register(spec, taskType string, payload any, opts ...extpoints.ScheduleOption) {
s.underlying.Register(spec, taskType, payload, opts...) s.underlying.Register(spec, taskType, payload, opts...)
s.ctx.OnDispose(func() error { s.ctx.OnDispose(func() error {
s.underlying.Unregister(taskType) s.underlying.Unregister(taskType)
@@ -149,7 +149,7 @@ func (s *scopedScheduleExtension) Register(spec string, taskType string, payload
}) })
} }
func (s *scopedScheduleExtension) RegisterCron(spec string, taskType string, payload any, opts ...extpoints.ScheduleOption) { func (s *scopedScheduleExtension) RegisterCron(spec, taskType string, payload any, opts ...extpoints.ScheduleOption) {
s.Register(spec, taskType, payload, opts...) s.Register(spec, taskType, payload, opts...)
} }
+1 -2
View File
@@ -4,11 +4,10 @@
package core package core
import ( import (
"Wavelet/core/extpoints"
"context" "context"
"errors" "errors"
"reflect" "reflect"
"Wavelet/core/extpoints"
) )
// Standard sentinel errors returned by core operations. // Standard sentinel errors returned by core operations.
@@ -6,12 +6,11 @@
package custom_example package custom_example
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core"
"Wavelet/core/contracts"
) )
// Plugin implements core.Plugin for the custom_example downstream plugin. // Plugin implements core.Plugin for the custom_example downstream plugin.
+1 -1
View File
@@ -242,7 +242,7 @@ func (w *Writer[T]) run() {
} }
} }
func (w *Writer[T]) shouldFlushOnInterval(batchLen int, batchStartedAt time.Time, now time.Time) bool { func (w *Writer[T]) shouldFlushOnInterval(batchLen int, batchStartedAt, now time.Time) bool {
if batchLen == 0 { if batchLen == 0 {
return false return false
} }
+2 -2
View File
@@ -26,7 +26,7 @@ const (
headerSize = 8 // 8 bytes metadata prefix for expiration UnixNano timestamp headerSize = 8 // 8 bytes metadata prefix for expiration UnixNano timestamp
defaultMaxSizeMB = 100 defaultMaxSizeMB = 100
defaultTTLMinutes = 60 defaultTTLMinutes = 60
cacheDirPerm = 0750 cacheDirPerm = 0o750
// DefaultExpiration applies the cache-wide default TTL. // DefaultExpiration applies the cache-wide default TTL.
DefaultExpiration time.Duration = 0 DefaultExpiration time.Duration = 0
@@ -284,7 +284,7 @@ func (c *Cache) Status() Status {
} }
// UpdatePolicy dynamically updates policies. // UpdatePolicy dynamically updates policies.
func (c *Cache) UpdatePolicy(maxSizeMB int64, ttlMinutes int64, lruEnabled bool) { func (c *Cache) UpdatePolicy(maxSizeMB, ttlMinutes int64, lruEnabled bool) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
+5 -5
View File
@@ -31,7 +31,7 @@ type CacheItem struct {
// Loader is an interface that the cache client must implement to handle database retrieval. // Loader is an interface that the cache client must implement to handle database retrieval.
type Loader interface { type Loader interface {
LoadAll(ctx context.Context, configType string) ([]CacheItem, error) LoadAll(ctx context.Context, configType string) ([]CacheItem, error)
LoadOne(ctx context.Context, configType string, key string) (CacheItem, error) LoadOne(ctx context.Context, configType, key string) (CacheItem, error)
} }
type cacheEntry struct { type cacheEntry struct {
@@ -59,7 +59,7 @@ func getWriteLock(configType string) *sync.Mutex {
// Get retrieves a cache item from the local cache store, checking for expiration. // Get retrieves a cache item from the local cache store, checking for expiration.
// Reads are completely lock-free because maps stored in Otter are immutable. // Reads are completely lock-free because maps stored in Otter are immutable.
func Get(configType string, key string) (CacheItem, bool) { func Get(configType, key string) (CacheItem, bool) {
m, ok := managerCache.GetIfPresent(configType) m, ok := managerCache.GetIfPresent(configType)
if !ok { if !ok {
return CacheItem{}, false return CacheItem{}, false
@@ -80,7 +80,7 @@ func Get(configType string, key string) (CacheItem, bool) {
return entry.item, true return entry.item, true
} }
func deleteKeyIfExpired(configType string, key string, expireAt time.Time) { func deleteKeyIfExpired(configType, key string, expireAt time.Time) {
lock := getWriteLock(configType) lock := getWriteLock(configType)
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
@@ -138,7 +138,7 @@ func Set(item CacheItem) {
// Delete removes a single item from the local cache store. // Delete removes a single item from the local cache store.
// Writes are protected by a fine-grained lock per configType. // Writes are protected by a fine-grained lock per configType.
func Delete(configType string, key string) { func Delete(configType, key string) {
lock := getWriteLock(configType) lock := getWriteLock(configType)
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
@@ -196,7 +196,7 @@ func GetTypeItems(configType string) []CacheItem {
} }
// Refresh reloads configuration cache from database via the Loader. // Refresh reloads configuration cache from database via the Loader.
func Refresh(ctx context.Context, configType string, key string, loader Loader) error { func Refresh(ctx context.Context, configType, key string, loader Loader) error {
if configType == "" { if configType == "" {
return errors.New("type is required") return errors.New("type is required")
} }
+1 -2
View File
@@ -118,8 +118,7 @@ type logConfig struct {
} }
// schedulerConfig 定时任务配置 // schedulerConfig 定时任务配置
type schedulerConfig struct { type schedulerConfig struct{}
}
// workerConfig 工作配置 // workerConfig 工作配置
type workerConfig struct { type workerConfig struct {
+1 -1
View File
@@ -52,7 +52,7 @@ func TestNewTransportUsesConfiguredDirectDialer(t *testing.T) {
dialer := &net.Dialer{} dialer := &net.Dialer{}
transport := NewTransport(TransportOptions{ transport := NewTransport(TransportOptions{
Proxy: nil, Proxy: nil,
DialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
dialedAddress = address dialedAddress = address
return dialer.DialContext(ctx, network, server.Listener.Addr().String()) return dialer.DialContext(ctx, network, server.Listener.Addr().String())
}, },
+1 -2
View File
@@ -5,12 +5,11 @@
package idgen package idgen
import ( import (
"Wavelet/pkg/config"
"fmt" "fmt"
"log" "log"
"github.com/bwmarrin/snowflake" "github.com/bwmarrin/snowflake"
"Wavelet/pkg/config"
) )
// 2025-12-01 00:00:00 UTC 的毫秒时间戳 // 2025-12-01 00:00:00 UTC 的毫秒时间戳
+1 -1
View File
@@ -99,7 +99,7 @@ func (r *LogRingBuffer) appendLine(line string) {
// cursor=0 表示查询最新日志,cursor>0 表示查询 index < cursor 的更早日志 // cursor=0 表示查询最新日志,cursor>0 表示查询 index < cursor 的更早日志
// limit 为返回条数上限 // limit 为返回条数上限
// 返回日志条目(按 index 升序)和是否有更早的日志 // 返回日志条目(按 index 升序)和是否有更早的日志
func (r *LogRingBuffer) Query(cursor int, limit int) ([]LogEntry, bool) { func (r *LogRingBuffer) Query(cursor, limit int) ([]LogEntry, bool) {
r.mu.RLock() r.mu.RLock()
defer r.mu.RUnlock() defer r.mu.RUnlock()
+1 -1
View File
@@ -17,7 +17,7 @@ import (
) )
// logDirPerm 日志目录权限 // logDirPerm 日志目录权限
const logDirPerm = 0750 const logDirPerm = 0o750
func getLogWriterForConfig(cfg Config) (zapcore.WriteSyncer, error) { func getLogWriterForConfig(cfg Config) (zapcore.WriteSyncer, error) {
if cfg.Output == "file" { if cfg.Output == "file" {
+4 -4
View File
@@ -38,12 +38,12 @@ func sanitizeHeaderValue(v string) string {
} }
// SendMail sends an HTML email using the provided config and message details // SendMail sends an HTML email using the provided config and message details
func SendMail(ctx context.Context, cfg Config, to string, subject, body string) error { func SendMail(ctx context.Context, cfg Config, to, subject, body string) error {
return SendMailHTML(ctx, cfg, to, subject, body) return SendMailHTML(ctx, cfg, to, subject, body)
} }
// SendMailHTML sends an HTML format email // SendMailHTML sends an HTML format email
func SendMailHTML(ctx context.Context, cfg Config, to string, subject, body string) error { func SendMailHTML(ctx context.Context, cfg Config, to, subject, body string) error {
addr := net.JoinHostPort(cfg.Host, strconv.Itoa(cfg.Port)) addr := net.JoinHostPort(cfg.Host, strconv.Itoa(cfg.Port))
// Header & MIME settings for HTML email // Header & MIME settings for HTML email
@@ -124,9 +124,9 @@ func sendMailViaSSL(ctx context.Context, addr string, auth smtp.Auth, cfg Config
} }
// SendMailWithLog sends a test email and records a detailed SMTP connection log // SendMailWithLog sends a test email and records a detailed SMTP connection log
func SendMailWithLog(ctx context.Context, cfg Config, to string, subject, body string) (string, error) { func SendMailWithLog(ctx context.Context, cfg Config, to, subject, body string) (string, error) {
var logBuf bytes.Buffer var logBuf bytes.Buffer
logLine := func(dir string, format string, args ...interface{}) { logLine := func(dir, format string, args ...interface{}) {
fmt.Fprintf(&logBuf, "[%s] %s\n", dir, fmt.Sprintf(format, args...)) fmt.Fprintf(&logBuf, "[%s] %s\n", dir, fmt.Sprintf(format, args...))
} }
+2 -2
View File
@@ -4,9 +4,9 @@
package testhelper package testhelper
import ( import (
"github.com/gin-gonic/gin"
"Wavelet/pkg/response" "Wavelet/pkg/response"
"github.com/gin-gonic/gin"
) )
// NewTestGinEngine 创建带 ErrorHandlerMiddleware 的 Gin 引擎,与生产环境错误响应行为一致。 // NewTestGinEngine 创建带 ErrorHandlerMiddleware 的 Gin 引擎,与生产环境错误响应行为一致。
+4 -2
View File
@@ -12,8 +12,10 @@ import (
) )
// Tracer 全局 OpenTelemetry Tracer 实例 // Tracer 全局 OpenTelemetry Tracer 实例
var Tracer trace.Tracer var (
var shutdownFuncs []func(context.Context) error Tracer trace.Tracer
shutdownFuncs []func(context.Context) error
)
func init() { func init() {
// 初始化 Propagator // 初始化 Propagator
+3 -3
View File
@@ -33,7 +33,7 @@ const (
// signKey: 64 字符 hex 编码的密钥(对应 32 字节,用于 AES-256) // signKey: 64 字符 hex 编码的密钥(对应 32 字节,用于 AES-256)
// plaintext: 要加密的明文字符串 // plaintext: 要加密的明文字符串
// return: base64 编码的密文 // return: base64 编码的密文
func Encrypt(signKey string, plaintext string) (string, error) { func Encrypt(signKey, plaintext string) (string, error) {
return encryptBytes(signKey, []byte(plaintext)) return encryptBytes(signKey, []byte(plaintext))
} }
@@ -41,7 +41,7 @@ func Encrypt(signKey string, plaintext string) (string, error) {
// signKey: 64 字符 hex 编码的密钥(对应 32 字节,用于 AES-256) // signKey: 64 字符 hex 编码的密钥(对应 32 字节,用于 AES-256)
// ciphertext: base64 编码的密文 // ciphertext: base64 编码的密文
// return: 解密后的明文字符串 // return: 解密后的明文字符串
func Decrypt(signKey string, ciphertext string) (string, error) { func Decrypt(signKey, ciphertext string) (string, error) {
plaintext, err := decryptBytes(signKey, ciphertext) plaintext, err := decryptBytes(signKey, ciphertext)
if err != nil { if err != nil {
return "", err return "", err
@@ -86,7 +86,7 @@ func encryptBytes(signKey string, plaintext []byte) (string, error) {
} }
// decryptBytes 解密函数,处理字节数据 // decryptBytes 解密函数,处理字节数据
func decryptBytes(signKey string, ciphertext string) ([]byte, error) { func decryptBytes(signKey, ciphertext string) ([]byte, error) {
// 将 hex 编码的密钥转换为字节 // 将 hex 编码的密钥转换为字节
key, err := hex.DecodeString(signKey) key, err := hex.DecodeString(signKey)
if err != nil { if err != nil {
+1 -2
View File
@@ -4,14 +4,13 @@
package util package util
import ( import (
"Wavelet/pkg/httppool"
"context" "context"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"time" "time"
"Wavelet/pkg/httppool"
) )
// IsLocalhost 检查 URL 是否为 localhost // IsLocalhost 检查 URL 是否为 localhost
+4 -2
View File
@@ -18,8 +18,10 @@ func HashPassword(password string) (string, error) {
return string(hash), nil return string(hash), nil
} }
var dummyPasswordHashOnce sync.Once var (
var dummyPasswordHash string dummyPasswordHashOnce sync.Once
dummyPasswordHash string
)
func dummyHash() string { func dummyHash() string {
dummyPasswordHashOnce.Do(func() { dummyPasswordHashOnce.Do(func() {
+1 -2
View File
@@ -4,12 +4,11 @@
package admin package admin
import ( import (
"Wavelet/core/contracts"
"context" "context"
"sync" "sync"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core/contracts"
) )
var ( var (
@@ -4,13 +4,12 @@
package admin package admin
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/response"
"net/http" "net/http"
"strconv" "strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core/contracts"
"Wavelet/pkg/response"
) )
// ListAuthSources lists all configured authentication sources. // ListAuthSources lists all configured authentication sources.
@@ -4,6 +4,7 @@
package admin package admin
import ( import (
"Wavelet/pkg/response"
"context" "context"
"net/http" "net/http"
"strconv" "strconv"
@@ -11,7 +12,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
pkgcache "Wavelet/pkg/cache/disk" pkgcache "Wavelet/pkg/cache/disk"
"Wavelet/pkg/response"
) )
type updateCacheConfigRequest struct { type updateCacheConfigRequest struct {
@@ -4,6 +4,9 @@
package admin package admin
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@@ -15,10 +18,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
mail "Wavelet/pkg/mail" mail "Wavelet/pkg/mail"
"Wavelet/pkg/response"
) )
const maskedConfigValue = "******" const maskedConfigValue = "******"
@@ -465,7 +465,7 @@ func maskSensitiveConfig(key, value string) string {
// validateAndMergeStorageConfig parses, merges unmasked secrets, validates parameter values, // validateAndMergeStorageConfig parses, merges unmasked secrets, validates parameter values,
// and tests connectivity of the new storage configuration. // and tests connectivity of the new storage configuration.
func validateAndMergeStorageConfig(ctx context.Context, value string, currentConfig string) (string, error) { func validateAndMergeStorageConfig(ctx context.Context, value, currentConfig string) (string, error) {
var currentCfg contracts.StorageConfigDTO var currentCfg contracts.StorageConfigDTO
if err := json.Unmarshal([]byte(currentConfig), &currentCfg); err != nil { if err := json.Unmarshal([]byte(currentConfig), &currentCfg); err != nil {
return "", fmt.Errorf("解析当前存储配置失败: %w", err) return "", fmt.Errorf("解析当前存储配置失败: %w", err)
+2 -3
View File
@@ -4,6 +4,8 @@
package admin package admin
import ( import (
"Wavelet/pkg/config"
"Wavelet/pkg/response"
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
@@ -17,9 +19,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/config"
"Wavelet/pkg/response"
) )
const ( const (
@@ -4,6 +4,11 @@
package admin package admin
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/config"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@@ -16,12 +21,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"Wavelet/core/contracts"
"Wavelet/pkg/config"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
) )
const ( const (
@@ -4,6 +4,9 @@
package admin package admin
import ( import (
"Wavelet/pkg/config"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@@ -14,10 +17,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/config"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
) )
var startTime = time.Now() var startTime = time.Now()
@@ -4,6 +4,9 @@
package admin package admin
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
@@ -12,10 +15,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
) )
// ListTaskTypes 获取支持的任务类型列表 // ListTaskTypes 获取支持的任务类型列表
@@ -4,14 +4,13 @@
package admin package admin
import ( import (
"Wavelet/pkg/response"
"context" "context"
"errors" "errors"
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/response"
) )
// CreateTemplateRequest 创建模板请求 // CreateTemplateRequest 创建模板请求
@@ -4,6 +4,10 @@
package admin package admin
import ( import (
"Wavelet/pkg/buildinfo"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
"archive/tar" "archive/tar"
"archive/zip" "archive/zip"
"compress/gzip" "compress/gzip"
@@ -23,11 +27,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
"Wavelet/pkg/buildinfo"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
) )
const ( const (
@@ -391,7 +390,7 @@ func matchBinaryName(name string, candidates []string) bool {
return false return false
} }
func getCandidateBinaryNames(executable string, repository string) []string { func getCandidateBinaryNames(executable, repository string) []string {
execName := filepath.Base(executable) execName := filepath.Base(executable)
names := []string{execName} names := []string{execName}
@@ -435,7 +434,7 @@ func isLikelyBinary(name string, isDir bool, mode os.FileMode) bool {
return filepath.Ext(base) == ".exe" return filepath.Ext(base) == ".exe"
} }
return (mode.Perm()&0111 != 0) || (filepath.Ext(base) == "") return (mode.Perm()&0o111 != 0) || (filepath.Ext(base) == "")
} }
func findBinaryInTarGz(archivePath string, candidates []string) (string, error) { func findBinaryInTarGz(archivePath string, candidates []string) (string, error) {
@@ -4,6 +4,10 @@
package admin package admin
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
"errors" "errors"
"net/http" "net/http"
"strconv" "strconv"
@@ -11,11 +15,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
) )
// listUsersRequest 用户列表查询请求 // listUsersRequest 用户列表查询请求
@@ -393,7 +392,6 @@ func UpdateUser(c *gin.Context) {
IsAdmin: req.IsAdmin, IsAdmin: req.IsAdmin,
Password: req.Password, Password: req.Password,
}) })
if err != nil { if err != nil {
if abortUserLogicError(c, err, userNotFound, []string{cannotRevokeSelfAdmin}, []string{emailRequired, emailExists, passwordTooShort}) { if abortUserLogicError(c, err, userNotFound, []string{cannotRevokeSelfAdmin}, []string{emailRequired, emailExists, passwordTooShort}) {
return return
+2 -2
View File
@@ -4,13 +4,13 @@
package admin package admin
import ( import (
"github.com/gin-gonic/gin"
"Wavelet/core/contracts" "Wavelet/core/contracts"
"Wavelet/pkg/logger" "Wavelet/pkg/logger"
"Wavelet/pkg/response" "Wavelet/pkg/response"
"Wavelet/pkg/trace" "Wavelet/pkg/trace"
"Wavelet/pkg/util" "Wavelet/pkg/util"
"github.com/gin-gonic/gin"
) )
// LoginAdminRequired 返回管理员权限校验中间件 // LoginAdminRequired 返回管理员权限校验中间件
+3 -4
View File
@@ -5,16 +5,15 @@
package admin package admin
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
"context" "context"
"embed" "embed"
"reflect" "reflect"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/hibiken/asynq" "github.com/hibiken/asynq"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
) )
//go:embed migrations/*/*.sql //go:embed migrations/*/*.sql
+2 -3
View File
@@ -4,14 +4,13 @@
package admin_test package admin_test
import ( import (
"Wavelet/core"
"Wavelet/plugins/domain/admin"
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
"Wavelet/plugins/domain/admin"
) )
func TestAdminPluginUnit(t *testing.T) { func TestAdminPluginUnit(t *testing.T) {
+5 -6
View File
@@ -4,6 +4,9 @@
package admin package admin
import ( import (
"Wavelet/pkg/cache/ram"
"Wavelet/pkg/idgen"
"Wavelet/pkg/util"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@@ -14,10 +17,6 @@ import (
"github.com/shopspring/decimal" "github.com/shopspring/decimal"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/cache/ram"
"Wavelet/pkg/idgen"
"Wavelet/pkg/util"
) )
const ( const (
@@ -62,7 +61,7 @@ func PreheatSystemConfigByKey(ctx context.Context, key string) (SystemConfig, er
} }
// GetSystemConfigByGroup queries a configuration by Type and Key. // GetSystemConfigByGroup queries a configuration by Type and Key.
func GetSystemConfigByGroup(ctx context.Context, configType string, key string) (SystemConfig, error) { func GetSystemConfigByGroup(ctx context.Context, configType, key string) (SystemConfig, error) {
ensureSystemConfigCacheListener() ensureSystemConfigCacheListener()
if item, ok := ram.Get(configType, key); ok { if item, ok := ram.Get(configType, key); ok {
@@ -479,7 +478,7 @@ func GetLatestTaskExecutionByTaskType(ctx context.Context, taskType string) (*Ta
} }
// AppendTaskExecutionLog 将日志追加到缓冲,任务完成后再持久化到数据库。 // AppendTaskExecutionLog 将日志追加到缓冲,任务完成后再持久化到数据库。
func AppendTaskExecutionLog(ctx context.Context, taskID string, logLine string) error { func AppendTaskExecutionLog(ctx context.Context, taskID, logLine string) error {
cacheSvc := GetCache(ctx) cacheSvc := GetCache(ctx)
if cacheSvc == nil { if cacheSvc == nil {
return errors.New("cache service is not initialized") return errors.New("cache service is not initialized")
+1 -2
View File
@@ -6,13 +6,12 @@
package admin package admin
import ( import (
"Wavelet/pkg/logger"
"context" "context"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"syscall" "syscall"
"Wavelet/pkg/logger"
) )
const installedBinaryMode = 0o755 const installedBinaryMode = 0o755
@@ -4,14 +4,13 @@
package admin package admin
import ( import (
"Wavelet/pkg/cache/ram"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"time" "time"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/cache/ram"
) )
const ( const (
@@ -57,7 +56,7 @@ func (ConfigLoader) LoadAll(ctx context.Context, configType string) ([]ram.Cache
} }
// LoadOne loads a single system config from database as CacheItem. // LoadOne loads a single system config from database as CacheItem.
func (ConfigLoader) LoadOne(ctx context.Context, configType string, key string) (ram.CacheItem, error) { func (ConfigLoader) LoadOne(ctx context.Context, configType, key string) (ram.CacheItem, error) {
cfg, err := GetSystemConfigByKey(ctx, key) cfg, err := GetSystemConfigByKey(ctx, key)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
+2 -3
View File
@@ -4,13 +4,12 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"context" "context"
"encoding/json" "encoding/json"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
) )
// LogForAudit 将登录鉴权审计日志写入 Logger // LogForAudit 将登录鉴权审计日志写入 Logger
@@ -4,14 +4,13 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"Wavelet/core/contracts"
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@@ -128,7 +127,7 @@ func containsScope(scopes []string, scope string) bool {
return false return false
} }
func buildOAuthUserInfo(ctx context.Context, source *AuthSource, code string, nonce string, redirectURL string) (*contracts.OAuthUserInfoDTO, error) { func buildOAuthUserInfo(ctx context.Context, source *AuthSource, code, nonce, redirectURL string) (*contracts.OAuthUserInfoDTO, error) {
authConfig, verifier, err := buildOAuthConfig(ctx, source, redirectURL) authConfig, verifier, err := buildOAuthConfig(ctx, source, redirectURL)
if err != nil { if err != nil {
return nil, err return nil, err
+2 -3
View File
@@ -4,12 +4,11 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/cache/ram"
"context" "context"
"fmt" "fmt"
"time" "time"
"Wavelet/core/contracts"
"Wavelet/pkg/cache/ram"
) )
const ( const (
+3 -4
View File
@@ -4,14 +4,13 @@
package auth_test package auth_test
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/auth"
"context" "context"
"encoding/json" "encoding/json"
"testing" "testing"
"time" "time"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/auth"
) )
type mockCacheService struct { type mockCacheService struct {
+5 -7
View File
@@ -4,6 +4,11 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/idgen"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@@ -12,18 +17,11 @@ import (
"strings" "strings"
"time" "time"
"Wavelet/core/contracts"
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/idgen"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
) )
// GetLoginSources 获取可用登录源列表 // GetLoginSources 获取可用登录源列表
+4 -5
View File
@@ -4,17 +4,16 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/response"
"Wavelet/pkg/trace"
"Wavelet/pkg/util"
"context" "context"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"errors" "errors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core/contracts"
"Wavelet/pkg/response"
"Wavelet/pkg/trace"
"Wavelet/pkg/util"
) )
func hashToken(token string) string { func hashToken(token string) string {
+1 -2
View File
@@ -4,14 +4,13 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"encoding/json" "encoding/json"
"errors" "errors"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"Wavelet/core/contracts"
) )
var authSourceNamePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$`) var authSourceNamePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$`)
+3 -4
View File
@@ -5,13 +5,12 @@
package auth package auth
import ( import (
"context"
"embed"
"reflect"
"Wavelet/core" "Wavelet/core"
"Wavelet/core/contracts" "Wavelet/core/contracts"
"Wavelet/core/extpoints" "Wavelet/core/extpoints"
"context"
"embed"
"reflect"
) )
//go:embed migrations/*/*.sql //go:embed migrations/*/*.sql
+4 -4
View File
@@ -4,6 +4,9 @@
package auth_test package auth_test
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/auth"
"context" "context"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
@@ -15,10 +18,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/auth"
) )
type mockDBService struct { type mockDBService struct {
@@ -84,6 +83,7 @@ func (m *mockProvider) Name() string { return "custom" }
func (m *mockProvider) GetAuthURL(state string) string { func (m *mockProvider) GetAuthURL(state string) string {
return "https://custom.com/auth?state=" + state return "https://custom.com/auth?state=" + state
} }
func (m *mockProvider) ExchangeCode(ctx context.Context, code string) (*contracts.OAuthUserInfoDTO, error) { func (m *mockProvider) ExchangeCode(ctx context.Context, code string) (*contracts.OAuthUserInfoDTO, error) {
return &contracts.OAuthUserInfoDTO{ return &contracts.OAuthUserInfoDTO{
ID: 555, ID: 555,
+3 -4
View File
@@ -4,13 +4,12 @@
package auth package auth
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"context" "context"
"sync" "sync"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core"
"Wavelet/core/contracts"
) )
var ( var (
@@ -120,6 +119,6 @@ func ListExternalAccountsByUserID(ctx context.Context, userID uint64) ([]Externa
} }
// UnbindExternalAccount 解绑外部账号 // UnbindExternalAccount 解绑外部账号
func UnbindExternalAccount(ctx context.Context, id uint64, userID uint64) error { func UnbindExternalAccount(ctx context.Context, id, userID uint64) error {
return getDB(ctx).Where("id = ? AND user_id = ?", id, userID).Delete(&ExternalAccount{}).Error return getDB(ctx).Where("id = ? AND user_id = ?", id, userID).Delete(&ExternalAccount{}).Error
} }
+2 -3
View File
@@ -4,14 +4,13 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/util"
"context" "context"
"errors" "errors"
"sync" "sync"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core/contracts"
"Wavelet/pkg/util"
) )
type authServiceImpl struct{} type authServiceImpl struct{}
+2 -3
View File
@@ -4,6 +4,8 @@
package auth package auth
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/config"
"context" "context"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
@@ -15,9 +17,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
gsessions "github.com/gorilla/sessions" gsessions "github.com/gorilla/sessions"
"Wavelet/core/contracts"
"Wavelet/pkg/config"
) )
// GetSessionOptions 根据配置构建 Session 选项 // GetSessionOptions 根据配置构建 Session 选项
+3 -4
View File
@@ -4,13 +4,12 @@
package cap package cap
import ( import (
"net/http"
"github.com/gin-gonic/gin"
"Wavelet/pkg/logger" "Wavelet/pkg/logger"
"Wavelet/pkg/response" "Wavelet/pkg/response"
"Wavelet/plugins/domain/cap/pow" "Wavelet/plugins/domain/cap/pow"
"net/http"
"github.com/gin-gonic/gin"
) )
// ChallengeResponse is a local type alias for the pow.ChallengeResponse struct // ChallengeResponse is a local type alias for the pow.ChallengeResponse struct
+3 -4
View File
@@ -5,6 +5,8 @@
package cap package cap
import ( import (
"Wavelet/pkg/config"
"Wavelet/plugins/domain/cap/pow"
"context" "context"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
@@ -12,9 +14,6 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"Wavelet/pkg/config"
"Wavelet/plugins/domain/cap/pow"
) )
const ( const (
@@ -116,7 +115,7 @@ func (m *Manager) Redeem(ctx context.Context, token string, solutions []int, sco
} }
// VerifyToken validates and consumes the redeem token (single-use). // VerifyToken validates and consumes the redeem token (single-use).
func (m *Manager) VerifyToken(ctx context.Context, token string, expectedScope string) (bool, error) { func (m *Manager) VerifyToken(ctx context.Context, token, expectedScope string) (bool, error) {
if token == "" { if token == "" {
return false, nil return false, nil
} }
+2 -2
View File
@@ -4,9 +4,9 @@
package cap package cap
import ( import (
"github.com/gin-gonic/gin"
"Wavelet/pkg/response" "Wavelet/pkg/response"
"github.com/gin-gonic/gin"
) )
// VerifyMiddleware returns a Gin middleware that checks and consumes the X-Cap-Token header. // VerifyMiddleware returns a Gin middleware that checks and consumes the X-Cap-Token header.
+1 -2
View File
@@ -5,11 +5,10 @@
package cap package cap
import ( import (
"reflect"
"Wavelet/core" "Wavelet/core"
"Wavelet/core/contracts" "Wavelet/core/contracts"
"Wavelet/core/extpoints" "Wavelet/core/extpoints"
"reflect"
) )
// Plugin implements core.Plugin to provide CAPTCHA generation, validation, and route protection. // Plugin implements core.Plugin to provide CAPTCHA generation, validation, and route protection.
+1 -1
View File
@@ -88,7 +88,7 @@ func RandomHex(byteLen int) string {
return hex.EncodeToString(bytes) return hex.EncodeToString(bytes)
} }
func jwtSign(payload []byte, secret []byte) string { func jwtSign(payload, secret []byte) string {
body := b64urlEncode(payload) body := b64urlEncode(payload)
sigInput := jwtHeaderB64 + "." + body sigInput := jwtHeaderB64 + "." + body
+6 -6
View File
@@ -14,12 +14,12 @@ import (
// Store defines the storage interface for challenge nonces and verification tokens // Store defines the storage interface for challenge nonces and verification tokens
type Store interface { type Store interface {
Get(ctx context.Context, key string) (string, bool, error) Get(ctx context.Context, key string) (string, bool, error)
Set(ctx context.Context, key string, val string, ttl time.Duration) error Set(ctx context.Context, key, val string, ttl time.Duration) error
Delete(ctx context.Context, key string) error Delete(ctx context.Context, key string) error
// SetNX atomically sets key=val with the given TTL only when the key does not // SetNX atomically sets key=val with the given TTL only when the key does not
// exist yet. It returns true when the key was actually written (i.e. this // exist yet. It returns true when the key was actually written (i.e. this
// caller "won" the race), and false when the key already existed. // caller "won" the race), and false when the key already existed.
SetNX(ctx context.Context, key string, val string, ttl time.Duration) (bool, error) SetNX(ctx context.Context, key, val string, ttl time.Duration) (bool, error)
// GetAndDelete atomically retrieves the value of key and removes it in a // GetAndDelete atomically retrieves the value of key and removes it in a
// single operation. Returns ("", false, nil) when the key does not exist. // single operation. Returns ("", false, nil) when the key does not exist.
GetAndDelete(ctx context.Context, key string) (string, bool, error) GetAndDelete(ctx context.Context, key string) (string, bool, error)
@@ -68,7 +68,7 @@ func (s *MemoryStore) getLocked(key string) (string, bool, error) {
} }
// Set 向 MemoryStore 写入指定 key 的值 // Set 向 MemoryStore 写入指定 key 的值
func (s *MemoryStore) Set(_ context.Context, key string, val string, ttl time.Duration) error { func (s *MemoryStore) Set(_ context.Context, key, val string, ttl time.Duration) error {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
s.items[key] = memoryItem{ s.items[key] = memoryItem{
@@ -88,7 +88,7 @@ func (s *MemoryStore) Delete(_ context.Context, key string) error {
// SetNX atomically sets key only when it is absent (or expired). // SetNX atomically sets key only when it is absent (or expired).
// Returns true if the key was written by this call. // Returns true if the key was written by this call.
func (s *MemoryStore) SetNX(_ context.Context, key string, val string, ttl time.Duration) (bool, error) { func (s *MemoryStore) SetNX(_ context.Context, key, val string, ttl time.Duration) (bool, error) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
@@ -159,7 +159,7 @@ func (s *RedisStore) Get(ctx context.Context, key string) (string, bool, error)
} }
// Set 向 RedisStore 写入指定 key 的值 // Set 向 RedisStore 写入指定 key 的值
func (s *RedisStore) Set(ctx context.Context, key string, val string, ttl time.Duration) error { func (s *RedisStore) Set(ctx context.Context, key, val string, ttl time.Duration) error {
return s.client.Set(ctx, key, val, ttl).Err() return s.client.Set(ctx, key, val, ttl).Err()
} }
@@ -169,7 +169,7 @@ func (s *RedisStore) Delete(ctx context.Context, key string) error {
} }
// SetNX wraps Redis SET NX – returns true only when the key was newly created. // SetNX wraps Redis SET NX – returns true only when the key was newly created.
func (s *RedisStore) SetNX(ctx context.Context, key string, val string, ttl time.Duration) (bool, error) { func (s *RedisStore) SetNX(ctx context.Context, key, val string, ttl time.Duration) (bool, error) {
return s.client.SetNX(ctx, key, val, ttl).Result() return s.client.SetNX(ctx, key, val, ttl).Result()
} }
@@ -4,6 +4,8 @@
package cap package cap
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"context" "context"
"errors" "errors"
"strconv" "strconv"
@@ -13,9 +15,6 @@ import (
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core"
"Wavelet/core/contracts"
) )
var ( var (
+10 -10
View File
@@ -4,6 +4,16 @@
package domain_test package domain_test
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/admin"
"Wavelet/plugins/domain/auth"
"Wavelet/plugins/domain/message_gateway"
"Wavelet/plugins/domain/risk_control"
"Wavelet/plugins/domain/user"
"Wavelet/plugins/infra/cache"
"Wavelet/plugins/infra/logger"
"Wavelet/plugins/infra/storage"
"context" "context"
"io/fs" "io/fs"
"path/filepath" "path/filepath"
@@ -16,17 +26,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/admin"
"Wavelet/plugins/domain/auth"
"Wavelet/plugins/domain/message_gateway"
"Wavelet/plugins/domain/risk_control"
"Wavelet/plugins/domain/user"
"Wavelet/plugins/infra/cache"
db "Wavelet/plugins/infra/database" db "Wavelet/plugins/infra/database"
"Wavelet/plugins/infra/logger"
"Wavelet/plugins/infra/storage"
) )
func setupTestDB(t *testing.T) *gorm.DB { func setupTestDB(t *testing.T) *gorm.DB {
@@ -4,12 +4,11 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/pkg/response"
"net/http" "net/http"
"strconv" "strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/pkg/response"
) )
// ListAdminChannelDefinitions returns form schemas for supported channel types. // ListAdminChannelDefinitions returns form schemas for supported channel types.
@@ -5,17 +5,15 @@
package qq package qq
import ( import (
"Wavelet/pkg/logger"
"Wavelet/pkg/util"
"Wavelet/plugins/domain/message_gateway"
"context" "context"
"fmt" "fmt"
"strings" "strings"
"sync" "sync"
"time" "time"
"Wavelet/pkg/util"
"Wavelet/pkg/logger"
"Wavelet/plugins/domain/message_gateway"
"github.com/tencent-connect/botgo" "github.com/tencent-connect/botgo"
"github.com/tencent-connect/botgo/dto" "github.com/tencent-connect/botgo/dto"
"github.com/tencent-connect/botgo/event" "github.com/tencent-connect/botgo/event"
@@ -4,10 +4,9 @@
package qq package qq
import ( import (
"Wavelet/plugins/domain/message_gateway"
"context" "context"
"testing" "testing"
"Wavelet/plugins/domain/message_gateway"
) )
func TestHandleEvent_DropsNonC2C(t *testing.T) { func TestHandleEvent_DropsNonC2C(t *testing.T) {
@@ -5,6 +5,8 @@
package telegram package telegram
import ( import (
"Wavelet/pkg/util"
"Wavelet/plugins/domain/message_gateway"
"context" "context"
"fmt" "fmt"
"os" "os"
@@ -13,9 +15,6 @@ import (
"strings" "strings"
tele "gopkg.in/telebot.v4" tele "gopkg.in/telebot.v4"
"Wavelet/pkg/util"
"Wavelet/plugins/domain/message_gateway"
) )
// Adapter is a Telegram private-chat channel. // Adapter is a Telegram private-chat channel.
@@ -4,12 +4,11 @@
package telegram package telegram
import ( import (
"Wavelet/plugins/domain/message_gateway"
"context" "context"
"testing" "testing"
tele "gopkg.in/telebot.v4" tele "gopkg.in/telebot.v4"
"Wavelet/plugins/domain/message_gateway"
) )
func TestHandleUpdate_DropsGroups(t *testing.T) { func TestHandleUpdate_DropsGroups(t *testing.T) {
@@ -4,10 +4,9 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core/contracts"
"context" "context"
"time" "time"
"Wavelet/core/contracts"
) )
// AdminLogin is the metadata definition for the admin login event. // AdminLogin is the metadata definition for the admin login event.
@@ -4,13 +4,12 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"context" "context"
"sync" "sync"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core"
"Wavelet/core/contracts"
) )
var ( var (
@@ -4,15 +4,14 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
"errors" "errors"
"net/http" "net/http"
"strconv" "strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core/contracts"
"Wavelet/pkg/response"
"Wavelet/pkg/util"
) )
func currentUser(c *gin.Context) (*contracts.UserDTO, bool) { func currentUser(c *gin.Context) (*contracts.UserDTO, bool) {
@@ -4,14 +4,13 @@
package message_gateway_test package message_gateway_test
import ( import (
"Wavelet/pkg/testhelper"
"Wavelet/plugins/domain/message_gateway"
"context" "context"
"testing" "testing"
"time" "time"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/testhelper"
"Wavelet/plugins/domain/message_gateway"
) )
type mockDBService struct { type mockDBService struct {
@@ -5,16 +5,15 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
"Wavelet/pkg/util"
"context" "context"
"embed" "embed"
"reflect" "reflect"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
"Wavelet/pkg/util"
) )
//go:embed migrations/*/*.sql //go:embed migrations/*/*.sql
@@ -4,15 +4,14 @@
package message_gateway_test package message_gateway_test
import ( import (
"Wavelet/core"
"Wavelet/plugins/domain/message_gateway"
"context" "context"
"io/fs" "io/fs"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"Wavelet/core"
"Wavelet/plugins/domain/message_gateway"
) )
func TestMessageGatewayPluginUnit(t *testing.T) { func TestMessageGatewayPluginUnit(t *testing.T) {
@@ -4,6 +4,7 @@
package push package push
import ( import (
"Wavelet/pkg/httppool"
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
@@ -12,8 +13,6 @@ import (
"io" "io"
"net/http" "net/http"
"strings" "strings"
"Wavelet/pkg/httppool"
) )
func init() { func init() {
@@ -4,14 +4,13 @@
package push package push
import ( import (
"Wavelet/pkg/util"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/smtp" "net/smtp"
"strings" "strings"
"Wavelet/pkg/util"
) )
func init() { func init() {
@@ -4,6 +4,7 @@
package push package push
import ( import (
"Wavelet/pkg/httppool"
"bytes" "bytes"
"context" "context"
"crypto/hmac" "crypto/hmac"
@@ -16,8 +17,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
"Wavelet/pkg/httppool"
) )
func init() { func init() {
@@ -4,6 +4,7 @@
package push package push
import ( import (
"Wavelet/pkg/httppool"
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
@@ -11,8 +12,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"Wavelet/pkg/httppool"
) )
func init() { func init() {
@@ -4,6 +4,7 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/pkg/response"
"encoding/json" "encoding/json"
"errors" "errors"
"net/http" "net/http"
@@ -14,7 +15,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/response"
pkgpush "Wavelet/plugins/domain/message_gateway/push" pkgpush "Wavelet/plugins/domain/message_gateway/push"
) )
@@ -4,18 +4,16 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/pkg/logger"
"Wavelet/pkg/util"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"sync" "sync"
"Wavelet/pkg/logger"
pkgpush "Wavelet/plugins/domain/message_gateway/push" pkgpush "Wavelet/plugins/domain/message_gateway/push"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/util"
) )
// NotificationMessage represents the structured notification message payload. // NotificationMessage represents the structured notification message payload.
@@ -122,7 +120,7 @@ func (t *EventTrigger) Trigger(ctx context.Context, meta EventMetadata, body map
}) })
} }
func (t *EventTrigger) buildMessage(event *PushEvent, meta EventMetadata, flatBody map[string]any, body map[string]any) (NotificationMessage, string) { func (t *EventTrigger) buildMessage(event *PushEvent, meta EventMetadata, flatBody, body map[string]any) (NotificationMessage, string) {
var msg NotificationMessage var msg NotificationMessage
renderedTemplate := "" renderedTemplate := ""
@@ -4,6 +4,7 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/pkg/response"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
@@ -13,8 +14,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/pkg/response"
) )
// UpdatePushEventRequest is the request body for updating a push event. // UpdatePushEventRequest is the request body for updating a push event.
@@ -4,6 +4,7 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core/contracts"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@@ -13,7 +14,6 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"Wavelet/core/contracts"
pkgpush "Wavelet/plugins/domain/message_gateway/push" pkgpush "Wavelet/plugins/domain/message_gateway/push"
) )
@@ -368,7 +368,7 @@ func resolveDynamicKeyword(target string, flatBody map[string]any) string {
return target return target
} }
func resolveTargetUser(ctx context.Context, resolved string, _ string) (contracts.UserDTO, bool) { func resolveTargetUser(ctx context.Context, resolved, _ string) (contracts.UserDTO, bool) {
var user contracts.UserDTO var user contracts.UserDTO
if id, err := strconv.ParseUint(resolved, 10, 64); err == nil { if id, err := strconv.ParseUint(resolved, 10, 64); err == nil {
if err := getDB(ctx).Table("w_users").Where("id = ?", id).First(&user).Error; err == nil { if err := getDB(ctx).Table("w_users").Where("id = ?", id).First(&user).Error; err == nil {
@@ -381,7 +381,7 @@ func resolveTargetUser(ctx context.Context, resolved string, _ string) (contract
return user, false return user, false
} }
func resolveSystemTarget(ctx context.Context, resolved string, channel string) (string, bool) { func resolveSystemTarget(ctx context.Context, resolved, channel string) (string, bool) {
if resolved != "系统" && resolved != "system" && resolved != "0" { if resolved != "系统" && resolved != "system" && resolved != "0" {
return "", false return "", false
} }
@@ -507,7 +507,7 @@ func getFlatBody(body map[string]any) map[string]any {
return flatResult return flatResult
} }
func flattenMap(prefix string, m map[string]any, result map[string]any) { func flattenMap(prefix string, m, result map[string]any) {
for k, v := range m { for k, v := range m {
key := k key := k
if prefix != "" { if prefix != "" {
@@ -4,13 +4,12 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"context" "context"
"encoding/json" "encoding/json"
"strconv" "strconv"
"time" "time"
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
) )
func handleTaskCompleted(ctx context.Context, e contracts.TaskCompletedEvent) { func handleTaskCompleted(ctx context.Context, e contracts.TaskCompletedEvent) {
@@ -59,7 +58,7 @@ func handleTaskCompleted(ctx context.Context, e contracts.TaskCompletedEvent) {
} }
} }
func extractUserFromMap(ctx context.Context, data map[string]any, body map[string]any) { func extractUserFromMap(ctx context.Context, data, body map[string]any) {
if u, exists := body["user"]; exists && u != nil { if u, exists := body["user"]; exists && u != nil {
return return
} }
@@ -4,14 +4,13 @@
package message_gateway package message_gateway
import ( import (
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/plugins/domain/message_gateway/push"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"Wavelet/core/contracts"
"Wavelet/pkg/logger"
"Wavelet/plugins/domain/message_gateway/push"
) )
const ( const (
@@ -101,7 +100,7 @@ func (h *PushHandler) Execute(ctx context.Context, payload []byte) error {
return nil return nil
} }
func (h *PushHandler) recordHistory(ctx context.Context, req SendPayload, status string, errMsg string) { func (h *PushHandler) recordHistory(ctx context.Context, req SendPayload, status, errMsg string) {
if dbErr := recordPushHistory(ctx, req, status, errMsg); dbErr != nil { if dbErr := recordPushHistory(ctx, req, status, errMsg); dbErr != nil {
logger.ErrorF(ctx, "[Push] 写入推送历史审计记录失败: %v", dbErr) logger.ErrorF(ctx, "[Push] 写入推送历史审计记录失败: %v", dbErr)
} }

Some files were not shown because too many files have changed in this diff Show More