refactor(core): align with cordis spatiotemporal composability architecture

- Purify core micro-kernel by removing context hardcoded helpers and reverse dependencies
- Eliminate init() side effects in infra plugins with reversible lifecycle disposal
- Completely isolate plugins by removing cross-plugin imports and using core/contracts
- Introduce TaskService and RiskControlService contracts for unified cross-plugin APIs
- Regenerate Swagger documentation and update developer guide matrix
- Achieve 0 violations in check_cordis_architecture.sh and 100% test pass
This commit is contained in:
ryan
2026-08-28 15:05:31 +08:00
parent fc7fae7b0e
commit 299ac30ee4
150 changed files with 4328 additions and 2923 deletions
+2 -1
View File
@@ -6,10 +6,11 @@ package cap
import (
"net/http"
"github.com/gin-gonic/gin"
"Wavelet/pkg/logger"
"Wavelet/pkg/response"
"Wavelet/plugins/domain/cap/pow"
"github.com/gin-gonic/gin"
)
// ChallengeResponse is a local type alias for the pow.ChallengeResponse struct
+1 -8
View File
@@ -15,7 +15,6 @@ import (
"Wavelet/pkg/config"
"Wavelet/plugins/domain/cap/pow"
db "Wavelet/plugins/infra/cache"
)
const (
@@ -186,13 +185,7 @@ func GetDefaultManager() *Manager {
return
}
var store pow.Store
if config.Config != nil && config.Config.Redis.Enabled && db.Redis != nil {
store = pow.NewRedisStore(db.Redis)
} else {
store = pow.NewMemoryStore(1 * time.Minute)
}
store := pow.NewMemoryStore(1 * time.Minute)
defaultManager = NewManager(secret, store)
})
return defaultManager
+18 -1
View File
@@ -29,7 +29,6 @@ func (p *Plugin) Name() string {
func (p *Plugin) Inject() []reflect.Type {
return []reflect.Type{
reflect.TypeFor[contracts.DBService](),
reflect.TypeFor[contracts.CacheService](),
}
}
@@ -45,6 +44,24 @@ func (p *Plugin) Manifest() core.Manifest {
// Apply registers the cap routes and settings into the Context.
func (p *Plugin) Apply(ctx *core.Context) error {
// 0. Bind DBService from Context
if db, err := core.Inject[contracts.DBService](ctx); err == nil && db != nil {
setDBService(db)
} else {
core.When[contracts.DBService](ctx, func(db contracts.DBService) {
setDBService(db)
})
}
ctx.OnDispose(func() error {
setDBService(nil)
return nil
})
// Listen to system config changed events to invalidate cached settings
ctx.Events().On(contracts.EventTopicConfigChanged, func(_ any) {
InvalidateRuntimeSettings()
})
// Register HTTP Routes
capGroup := ctx.Router().Group("/api/v1/cap")
{
+41 -41
View File
@@ -5,7 +5,6 @@ package cap
import (
"context"
"encoding/json"
"errors"
"strconv"
"sync"
@@ -13,12 +12,38 @@ import (
"time"
"golang.org/x/sync/singleflight"
"gorm.io/gorm"
"Wavelet/pkg/util"
cachepkg "Wavelet/plugins/infra/cache"
database "Wavelet/plugins/infra/database"
"Wavelet/core"
"Wavelet/core/contracts"
)
var (
dbMu sync.RWMutex
dbSvc contracts.DBService
)
func setDBService(s contracts.DBService) {
dbMu.Lock()
defer dbMu.Unlock()
dbSvc = s
}
func getDB(ctx context.Context) *gorm.DB {
if c, ok := ctx.(*core.Context); ok && c != nil {
if s, err := core.Inject[contracts.DBService](c); err == nil && s != nil {
return s.DB(ctx)
}
}
dbMu.RLock()
s := dbSvc
dbMu.RUnlock()
if s != nil {
return s.DB(ctx)
}
return nil
}
const (
defaultChallengeCount = 1
defaultChallengeSize = 32
@@ -67,9 +92,8 @@ var runtimeConfigKeySet = func() map[string]struct{} {
}()
type runtimeSettingsStore struct {
snapshot atomic.Pointer[RuntimeSettings]
loadGroup singleflight.Group
listenerOnce sync.Once
snapshot atomic.Pointer[RuntimeSettings]
loadGroup singleflight.Group
}
var settingsStore = &runtimeSettingsStore{}
@@ -148,7 +172,11 @@ func loadRuntimeSettings(ctx context.Context) (RuntimeSettings, error) {
Value string `gorm:"column:value"`
}
var records []configRecord
if err := database.DB(ctx).Table("w_system_configs").Where("key IN ?", runtimeConfigKeys).Find(&records).Error; err != nil {
db := getDB(ctx)
if db == nil {
return parseRuntimeSettings(nil), nil
}
if err := db.Table("w_system_configs").Where("key IN ?", runtimeConfigKeys).Find(&records).Error; err != nil {
return RuntimeSettings{}, err
}
configs := make(map[string]string, len(records))
@@ -167,6 +195,10 @@ func parseRuntimeSettings(configs map[string]string) RuntimeSettings {
TokenTTL: defaultTokenTTL,
}
if len(configs) == 0 {
return settings
}
if val, ok := configs[ConfigKeyCapLoginEnabled]; ok {
if enabled, err := strconv.ParseBool(val); err == nil {
settings.LoginEnabled = enabled
@@ -201,36 +233,4 @@ func parseRuntimeSettings(configs map[string]string) RuntimeSettings {
return settings
}
func (s *runtimeSettingsStore) ensureInvalidationListener() {
s.listenerOnce.Do(startRuntimeSettingsInvalidationListener)
}
// SystemConfigInvalidationChannel 系统配置失效广播通道
const SystemConfigInvalidationChannel = "system_config:invalidation"
func startRuntimeSettingsInvalidationListener() {
rdb := cachepkg.Redis
if rdb == nil {
return
}
util.Go(func() {
pubsub := rdb.Subscribe(context.Background(), SystemConfigInvalidationChannel)
defer func() {
_ = pubsub.Close()
}()
for msg := range pubsub.Channel() {
var payload struct {
Key string `json:"key"`
}
if err := json.Unmarshal([]byte(msg.Payload), &payload); err != nil {
InvalidateRuntimeSettings()
continue
}
if payload.Key == "" || payload.Key == "*" || IsRuntimeConfigKey(payload.Key) {
InvalidateRuntimeSettings()
}
}
})
}
func (s *runtimeSettingsStore) ensureInvalidationListener() {}