4 changed files with 362 additions and 234 deletions
-
119weed/worker/tasks/balance/ui.go
-
123weed/worker/tasks/erasure_coding/ui.go
-
218weed/worker/tasks/ui_base.go
-
136weed/worker/tasks/vacuum/ui.go
@ -0,0 +1,218 @@ |
|||||
|
package tasks |
||||
|
|
||||
|
import ( |
||||
|
"reflect" |
||||
|
|
||||
|
"github.com/seaweedfs/seaweedfs/weed/glog" |
||||
|
"github.com/seaweedfs/seaweedfs/weed/worker/types" |
||||
|
) |
||||
|
|
||||
|
// BaseUIProvider provides common UIProvider functionality for all tasks
|
||||
|
type BaseUIProvider struct { |
||||
|
taskType types.TaskType |
||||
|
displayName string |
||||
|
description string |
||||
|
icon string |
||||
|
schemaFunc func() *TaskConfigSchema |
||||
|
configFunc func() interface{} |
||||
|
applyFunc func(config interface{}) error |
||||
|
} |
||||
|
|
||||
|
// NewBaseUIProvider creates a new base UI provider
|
||||
|
func NewBaseUIProvider( |
||||
|
taskType types.TaskType, |
||||
|
displayName string, |
||||
|
description string, |
||||
|
icon string, |
||||
|
schemaFunc func() *TaskConfigSchema, |
||||
|
configFunc func() interface{}, |
||||
|
applyFunc func(config interface{}) error, |
||||
|
) *BaseUIProvider { |
||||
|
return &BaseUIProvider{ |
||||
|
taskType: taskType, |
||||
|
displayName: displayName, |
||||
|
description: description, |
||||
|
icon: icon, |
||||
|
schemaFunc: schemaFunc, |
||||
|
configFunc: configFunc, |
||||
|
applyFunc: applyFunc, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// GetTaskType returns the task type
|
||||
|
func (ui *BaseUIProvider) GetTaskType() types.TaskType { |
||||
|
return ui.taskType |
||||
|
} |
||||
|
|
||||
|
// GetDisplayName returns the human-readable name
|
||||
|
func (ui *BaseUIProvider) GetDisplayName() string { |
||||
|
return ui.displayName |
||||
|
} |
||||
|
|
||||
|
// GetDescription returns a description of what this task does
|
||||
|
func (ui *BaseUIProvider) GetDescription() string { |
||||
|
return ui.description |
||||
|
} |
||||
|
|
||||
|
// GetIcon returns the icon CSS class for this task type
|
||||
|
func (ui *BaseUIProvider) GetIcon() string { |
||||
|
return ui.icon |
||||
|
} |
||||
|
|
||||
|
// GetCurrentConfig returns the current configuration
|
||||
|
func (ui *BaseUIProvider) GetCurrentConfig() interface{} { |
||||
|
return ui.configFunc() |
||||
|
} |
||||
|
|
||||
|
// ApplyConfig applies the new configuration with common schema-based handling
|
||||
|
func (ui *BaseUIProvider) ApplyConfig(config interface{}) error { |
||||
|
// First try direct application
|
||||
|
if err := ui.applyFunc(config); err == nil { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// Fallback: Try to get the configuration from the schema-based system
|
||||
|
schema := ui.schemaFunc() |
||||
|
if schema != nil { |
||||
|
// Apply defaults to ensure we have a complete config
|
||||
|
if err := schema.ApplyDefaults(config); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
// Try again with defaults applied
|
||||
|
if err := ui.applyFunc(config); err == nil { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// Last resort: use current config
|
||||
|
glog.Warningf("Config type conversion failed for %s, using current config", ui.taskType) |
||||
|
currentConfig := ui.GetCurrentConfig() |
||||
|
return ui.applyFunc(currentConfig) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// CommonConfigGetter provides a common pattern for getting current configuration
|
||||
|
type CommonConfigGetter[T any] struct { |
||||
|
defaultConfig T |
||||
|
detectorFunc func() T |
||||
|
schedulerFunc func() T |
||||
|
} |
||||
|
|
||||
|
// NewCommonConfigGetter creates a new common config getter
|
||||
|
func NewCommonConfigGetter[T any]( |
||||
|
defaultConfig T, |
||||
|
detectorFunc func() T, |
||||
|
schedulerFunc func() T, |
||||
|
) *CommonConfigGetter[T] { |
||||
|
return &CommonConfigGetter[T]{ |
||||
|
defaultConfig: defaultConfig, |
||||
|
detectorFunc: detectorFunc, |
||||
|
schedulerFunc: schedulerFunc, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// GetConfig returns the merged configuration
|
||||
|
func (cg *CommonConfigGetter[T]) GetConfig() T { |
||||
|
config := cg.defaultConfig |
||||
|
|
||||
|
// Apply detector values if available
|
||||
|
if cg.detectorFunc != nil { |
||||
|
detectorConfig := cg.detectorFunc() |
||||
|
mergeConfigs(&config, detectorConfig) |
||||
|
} |
||||
|
|
||||
|
// Apply scheduler values if available
|
||||
|
if cg.schedulerFunc != nil { |
||||
|
schedulerConfig := cg.schedulerFunc() |
||||
|
mergeConfigs(&config, schedulerConfig) |
||||
|
} |
||||
|
|
||||
|
return config |
||||
|
} |
||||
|
|
||||
|
// mergeConfigs merges non-zero values from source into dest
|
||||
|
func mergeConfigs[T any](dest *T, source T) { |
||||
|
destValue := reflect.ValueOf(dest).Elem() |
||||
|
sourceValue := reflect.ValueOf(source) |
||||
|
|
||||
|
if destValue.Kind() != reflect.Struct || sourceValue.Kind() != reflect.Struct { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
for i := 0; i < destValue.NumField(); i++ { |
||||
|
destField := destValue.Field(i) |
||||
|
sourceField := sourceValue.Field(i) |
||||
|
|
||||
|
if !destField.CanSet() { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
// Only copy non-zero values
|
||||
|
if !isZeroValue(sourceField) { |
||||
|
if destField.Type() == sourceField.Type() { |
||||
|
destField.Set(sourceField) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// isZeroValue checks if a reflect.Value represents a zero value
|
||||
|
func isZeroValue(v reflect.Value) bool { |
||||
|
switch v.Kind() { |
||||
|
case reflect.Bool: |
||||
|
return !v.Bool() |
||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
||||
|
return v.Int() == 0 |
||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
||||
|
return v.Uint() == 0 |
||||
|
case reflect.Float32, reflect.Float64: |
||||
|
return v.Float() == 0 |
||||
|
case reflect.String: |
||||
|
return v.String() == "" |
||||
|
case reflect.Slice, reflect.Map, reflect.Array: |
||||
|
return v.IsNil() || v.Len() == 0 |
||||
|
case reflect.Interface, reflect.Ptr: |
||||
|
return v.IsNil() |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
// RegisterUIFunc provides a common registration function signature
|
||||
|
type RegisterUIFunc[D, S any] func(uiRegistry *types.UIRegistry, detector D, scheduler S) |
||||
|
|
||||
|
// CommonRegisterUI provides a common registration implementation
|
||||
|
func CommonRegisterUI[D, S any]( |
||||
|
taskType types.TaskType, |
||||
|
displayName string, |
||||
|
uiRegistry *types.UIRegistry, |
||||
|
detector D, |
||||
|
scheduler S, |
||||
|
schemaFunc func() *TaskConfigSchema, |
||||
|
configFunc func() interface{}, |
||||
|
applyFunc func(config interface{}) error, |
||||
|
) { |
||||
|
// Get metadata from schema
|
||||
|
schema := schemaFunc() |
||||
|
description := "Task configuration" |
||||
|
icon := "fas fa-cog" |
||||
|
|
||||
|
if schema != nil { |
||||
|
description = schema.Description |
||||
|
icon = schema.Icon |
||||
|
} |
||||
|
|
||||
|
uiProvider := NewBaseUIProvider( |
||||
|
taskType, |
||||
|
displayName, |
||||
|
description, |
||||
|
icon, |
||||
|
schemaFunc, |
||||
|
configFunc, |
||||
|
applyFunc, |
||||
|
) |
||||
|
|
||||
|
uiRegistry.RegisterUI(uiProvider) |
||||
|
glog.V(1).Infof("✅ Registered %s task UI provider", taskType) |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue