You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

218 lines
5.4 KiB

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)
}