85 lines
2.4 KiB
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
|
|
}
|
|
}
|