proxy-pool/internal/controller/admin/configuration.go

85 lines
2.4 KiB
Go

package admin
import (
"bytes"
"context"
"errors"
"fmt"
"reflect"
"strings"
"proxy-pool/internal/config"
"proxy-pool/internal/domain/adminstate"
)
var ErrInvalidConfigurationLoader = errors.New("invalid admin configuration loader")
type FileConfigurationLoader struct {
path string
resolver config.Resolver
}
func NewFileConfigurationLoader(path string, resolver config.Resolver) (*FileConfigurationLoader, error) {
if strings.TrimSpace(path) != path || path == "" || len(path) > adminstate.MaxSourceBytes || nilInterface(resolver) {
return nil, ErrInvalidConfigurationLoader
}
return &FileConfigurationLoader{path: path, resolver: resolver}, nil
}
func (loader *FileConfigurationLoader) LoadConfiguration(ctx context.Context) (LoadedConfiguration, error) {
if loader == nil || ctx == nil {
return LoadedConfiguration{}, ErrInvalidConfigurationLoader
}
if err := ctx.Err(); err != nil {
return LoadedConfiguration{}, err
}
content, err := loader.resolver.ReadFile(loader.path)
if err != nil {
return LoadedConfiguration{}, errors.Join(ErrUnavailable,
fmt.Errorf("read configuration %q: %w", loader.path, err))
}
if err := ctx.Err(); err != nil {
return LoadedConfiguration{}, err
}
resolver := &observedConfigurationResolver{Resolver: loader.resolver}
configuration, err := config.LoadResolved(bytes.NewReader(content), resolver)
if err != nil {
if resolver.readErr != nil {
return LoadedConfiguration{}, errors.Join(ErrUnavailable,
fmt.Errorf("load configuration %q: %w", loader.path, err))
}
return LoadedConfiguration{}, errors.Join(ErrInvalidConfiguration,
fmt.Errorf("load configuration %q: %w", loader.path, err))
}
if err := ctx.Err(); err != nil {
return LoadedConfiguration{}, err
}
return LoadedConfiguration{Value: configuration, Source: loader.path}, nil
}
type observedConfigurationResolver struct {
config.Resolver
readErr error
}
func (resolver *observedConfigurationResolver) ReadFile(path string) ([]byte, error) {
content, err := resolver.Resolver.ReadFile(path)
if err != nil {
resolver.readErr = err
}
return content, err
}
func nilInterface(value any) bool {
if value == nil {
return true
}
reflected := reflect.ValueOf(value)
switch reflected.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
return reflected.IsNil()
default:
return false
}
}