mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-05 15:26:36 +08:00
Merge branch 'wavelet/main' into main
This commit is contained in:
@@ -10,13 +10,18 @@ import (
|
||||
|
||||
// SystemConfigDTO represents a system configuration key-value entry.
|
||||
type SystemConfigDTO struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
Type string `json:"type"`
|
||||
Visibility int `json:"visibility"`
|
||||
Description string `json:"description"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Key string `json:"key" gorm:"primaryKey;column:key;size:255"`
|
||||
Value string `json:"value" gorm:"column:value;type:text"`
|
||||
Type string `json:"type" gorm:"column:type;size:50"`
|
||||
Visibility int `json:"visibility" gorm:"column:visibility"`
|
||||
Description string `json:"description" gorm:"column:description;size:500"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
|
||||
}
|
||||
|
||||
// TableName returns the default table name for SystemConfigDTO.
|
||||
func (SystemConfigDTO) TableName() string {
|
||||
return "w_system_configs"
|
||||
}
|
||||
|
||||
// SystemConfigService defines the unified contract for querying and mutating system configurations.
|
||||
|
||||
@@ -71,6 +71,11 @@ type TaskExecutionDTO struct {
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TableName returns the default table name for TaskExecutionDTO.
|
||||
func (TaskExecutionDTO) TableName() string {
|
||||
return "w_task_executions"
|
||||
}
|
||||
|
||||
// Canonical triggered_by values persisted on task executions and shown in admin UI.
|
||||
const (
|
||||
TaskTriggerSystem = "system"
|
||||
|
||||
@@ -23,20 +23,25 @@ type UploadMetadataDTO struct {
|
||||
|
||||
// UploadDTO represents an uploaded file record.
|
||||
type UploadDTO struct {
|
||||
ID uint64 `json:"id"`
|
||||
UserID uint64 `json:"user_id"`
|
||||
FileName string `json:"file_name"`
|
||||
FilePath string `json:"file_path"`
|
||||
MimeType string `json:"mime_type"`
|
||||
ID uint64 `json:"id" gorm:"primaryKey"`
|
||||
UserID uint64 `json:"user_id" gorm:"index"`
|
||||
FileName string `json:"file_name" gorm:"size:255"`
|
||||
FilePath string `json:"file_path" gorm:"size:500"`
|
||||
MimeType string `json:"mime_type" gorm:"size:100"`
|
||||
Size int64 `json:"size"`
|
||||
Hash string `json:"hash"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
Metadata UploadMetadataDTO `json:"metadata"`
|
||||
Hash string `json:"hash" gorm:"size:64"`
|
||||
Status string `json:"status" gorm:"type:varchar(20)"`
|
||||
Type string `json:"type" gorm:"size:50;index"`
|
||||
Metadata UploadMetadataDTO `json:"metadata" gorm:"serializer:json;type:jsonb"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TableName returns the default table name for UploadDTO.
|
||||
func (UploadDTO) TableName() string {
|
||||
return "w_uploads"
|
||||
}
|
||||
|
||||
// OpenedUploadDTO encapsulates the retrieved object stream and its metadata.
|
||||
type OpenedUploadDTO struct {
|
||||
Upload UploadDTO
|
||||
|
||||
@@ -29,6 +29,7 @@ func (PublicConfigAdapter) PublicConfig(ctx context.Context) (map[string]string,
|
||||
// SystemConfigServiceImpl implements contracts.SystemConfigService.
|
||||
type SystemConfigServiceImpl struct{}
|
||||
|
||||
// GetByKey retrieves a system config by its unique key.
|
||||
func (SystemConfigServiceImpl) GetByKey(ctx context.Context, key string) (contracts.SystemConfigDTO, error) {
|
||||
cfg, err := repository.GetSystemConfigByKey(ctx, key)
|
||||
if err != nil {
|
||||
@@ -37,6 +38,7 @@ func (SystemConfigServiceImpl) GetByKey(ctx context.Context, key string) (contra
|
||||
return toSystemConfigDTO(cfg), nil
|
||||
}
|
||||
|
||||
// ListByKeys retrieves multiple system configs by their keys.
|
||||
func (SystemConfigServiceImpl) ListByKeys(ctx context.Context, keys []string) (map[string]contracts.SystemConfigDTO, error) {
|
||||
cfgs, err := repository.ListSystemConfigsByKeys(ctx, keys)
|
||||
if err != nil {
|
||||
@@ -49,6 +51,7 @@ func (SystemConfigServiceImpl) ListByKeys(ctx context.Context, keys []string) (m
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ListVisible returns all user-visible system configs.
|
||||
func (SystemConfigServiceImpl) ListVisible(ctx context.Context) ([]contracts.SystemConfigDTO, error) {
|
||||
cfgs, err := repository.ListVisibleSystemConfigs(ctx)
|
||||
if err != nil {
|
||||
@@ -61,6 +64,7 @@ func (SystemConfigServiceImpl) ListVisible(ctx context.Context) ([]contracts.Sys
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ListByType returns all system configs belonging to a specific configuration type.
|
||||
func (SystemConfigServiceImpl) ListByType(ctx context.Context, configType string) ([]contracts.SystemConfigDTO, error) {
|
||||
cfgs, err := repository.ListAdminSystemConfigs(ctx, configType)
|
||||
if err != nil {
|
||||
@@ -73,22 +77,27 @@ func (SystemConfigServiceImpl) ListByType(ctx context.Context, configType string
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetIntByKey retrieves an integer system config value.
|
||||
func (SystemConfigServiceImpl) GetIntByKey(ctx context.Context, key string) (int, error) {
|
||||
return repository.GetIntByKey(ctx, key)
|
||||
}
|
||||
|
||||
// GetBoolByKey retrieves a boolean system config value.
|
||||
func (SystemConfigServiceImpl) GetBoolByKey(ctx context.Context, key string) (bool, error) {
|
||||
return repository.GetBoolByKey(ctx, key)
|
||||
}
|
||||
|
||||
// SaveOrUpdate persists or updates a system config key-value pair.
|
||||
func (SystemConfigServiceImpl) SaveOrUpdate(ctx context.Context, key, value string) error {
|
||||
return repository.SaveOrUpdateSystemConfig(ctx, key, value)
|
||||
}
|
||||
|
||||
// InvalidateCache evicts the cache entry for the specified key.
|
||||
func (SystemConfigServiceImpl) InvalidateCache(ctx context.Context, key string) error {
|
||||
return repository.InvalidateSystemConfigCache(ctx, key)
|
||||
}
|
||||
|
||||
// InvalidateAllCaches purges all system configuration cache entries.
|
||||
func (SystemConfigServiceImpl) InvalidateAllCaches(ctx context.Context) error {
|
||||
return repository.InvalidateAllSystemConfigCaches(ctx)
|
||||
}
|
||||
|
||||
@@ -69,15 +69,15 @@ func (s *uploadServiceImpl) RebuildStats(ctx context.Context) error {
|
||||
|
||||
func toUploadDTO(u *models.Upload) contracts.UploadDTO {
|
||||
return contracts.UploadDTO{
|
||||
ID: u.ID,
|
||||
UserID: u.UserID,
|
||||
FileName: u.FileName,
|
||||
FilePath: u.FilePath,
|
||||
MimeType: u.MimeType,
|
||||
Size: u.FileSize,
|
||||
Hash: u.Hash,
|
||||
Status: string(u.Status),
|
||||
Type: u.Type,
|
||||
ID: u.ID,
|
||||
UserID: u.UserID,
|
||||
FileName: u.FileName,
|
||||
FilePath: u.FilePath,
|
||||
MimeType: u.MimeType,
|
||||
Size: u.FileSize,
|
||||
Hash: u.Hash,
|
||||
Status: string(u.Status),
|
||||
Type: u.Type,
|
||||
Metadata: contracts.UploadMetadataDTO{
|
||||
Width: u.Metadata.Width,
|
||||
Height: u.Metadata.Height,
|
||||
|
||||
@@ -112,30 +112,25 @@ func (s *inprocTaskService) ListExecutions(ctx context.Context, taskType, status
|
||||
return res, total, nil
|
||||
}
|
||||
|
||||
func (s *inprocTaskService) GetExecution(ctx context.Context, id uint64) (*contracts.TaskExecutionDTO, error) {
|
||||
func findExecution(ctx context.Context, query any, args ...any) (*contracts.TaskExecutionDTO, error) {
|
||||
db := getDB(ctx)
|
||||
if db == nil {
|
||||
return nil, errors.New("driver_inproc_worker: db not initialized")
|
||||
}
|
||||
var exec taskExecution
|
||||
if err := db.Where("id = ?", id).First(&exec).Error; err != nil {
|
||||
if err := db.Where(query, args...).First(&exec).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := toExecutionDTO(&exec)
|
||||
return &dto, nil
|
||||
}
|
||||
|
||||
func (s *inprocTaskService) GetExecution(ctx context.Context, id uint64) (*contracts.TaskExecutionDTO, error) {
|
||||
return findExecution(ctx, "id = ?", id)
|
||||
}
|
||||
|
||||
func (s *inprocTaskService) GetExecutionByTaskID(ctx context.Context, taskID string) (*contracts.TaskExecutionDTO, error) {
|
||||
db := getDB(ctx)
|
||||
if db == nil {
|
||||
return nil, errors.New("driver_inproc_worker: db not initialized")
|
||||
}
|
||||
var exec taskExecution
|
||||
if err := db.Where("task_id = ?", taskID).First(&exec).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := toExecutionDTO(&exec)
|
||||
return &dto, nil
|
||||
return findExecution(ctx, "task_id = ?", taskID)
|
||||
}
|
||||
|
||||
func toExecutionDTO(exec *taskExecution) contracts.TaskExecutionDTO {
|
||||
|
||||
@@ -19,6 +19,13 @@ import (
|
||||
// DefaultFileName is the configuration file looked up when CONFIG_PATH is unset.
|
||||
const DefaultFileName = "config.yaml"
|
||||
|
||||
// DefaultCandidates defines the prioritized list of configuration file paths looked up
|
||||
// when CONFIG_PATH is unset.
|
||||
var DefaultCandidates = []string{
|
||||
"manifest/config/config.yaml",
|
||||
DefaultFileName,
|
||||
}
|
||||
|
||||
// EnvOnlyOrigin is reported by Describe when no configuration file was loaded.
|
||||
const EnvOnlyOrigin = "<env only>"
|
||||
|
||||
@@ -56,7 +63,7 @@ func NewSource(opts ...Option) (*Source, error) {
|
||||
s.path = os.Getenv("CONFIG_PATH")
|
||||
}
|
||||
if s.path == "" {
|
||||
s.path = findConfigPath(DefaultFileName)
|
||||
s.path = findConfigPath(DefaultCandidates...)
|
||||
}
|
||||
|
||||
v := viper.New()
|
||||
@@ -107,20 +114,28 @@ func (s *Source) Describe() string {
|
||||
return s.path
|
||||
}
|
||||
|
||||
// findConfigPath searches upward from the working directory so tests and binaries run
|
||||
// from backend/ still find the repository-root configuration file.
|
||||
func findConfigPath(configPath string) string {
|
||||
if _, err := os.Stat(configPath); err == nil {
|
||||
return configPath
|
||||
// findConfigPath searches upward from the working directory through candidate paths so
|
||||
// tests and binaries run from subdirectories still find configuration files in manifest/config/
|
||||
// or the repository root.
|
||||
func findConfigPath(candidates ...string) string {
|
||||
if len(candidates) == 0 {
|
||||
return DefaultFileName
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
if _, err := os.Stat(candidate); err == nil {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
dir := "."
|
||||
for range maxSearchDepth {
|
||||
dir += "/.."
|
||||
path := dir + "/" + configPath
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return path
|
||||
for _, candidate := range candidates {
|
||||
path := dir + "/" + candidate
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
return configPath
|
||||
return candidates[0]
|
||||
}
|
||||
|
||||
@@ -91,3 +91,32 @@ func TestSourcePrefersConfigPathEnvironmentVariable(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, ":9100", value)
|
||||
}
|
||||
|
||||
func TestSourceFindsManifestConfigInParentDirectory(t *testing.T) {
|
||||
tempRoot := t.TempDir()
|
||||
manifestConfigDir := filepath.Join(tempRoot, "manifest", "config")
|
||||
require.NoError(t, os.MkdirAll(manifestConfigDir, 0o755))
|
||||
require.NoError(t, os.WriteFile(
|
||||
filepath.Join(manifestConfigDir, "config.yaml"),
|
||||
[]byte("app:\n addr: \":9200\"\n"),
|
||||
0o600,
|
||||
))
|
||||
|
||||
subDir := filepath.Join(tempRoot, "backend", "cmd")
|
||||
require.NoError(t, os.MkdirAll(subDir, 0o755))
|
||||
|
||||
origWd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, os.Chdir(subDir))
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(origWd)
|
||||
})
|
||||
|
||||
t.Setenv("CONFIG_PATH", "")
|
||||
|
||||
src, err := config.NewSource()
|
||||
require.NoError(t, err)
|
||||
value, ok := src.Lookup("app.addr")
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, ":9200", value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user