// Copyright 2024 Matthew Rich . All rights reserved. package config import ( _ "context" _ "encoding/json" _ "fmt" _ "gopkg.in/yaml.v3" "net/url" "path/filepath" "decl/internal/transport" "decl/internal/codec" _ "os" "io" "errors" "log/slog" ) type ConfigFile struct { Path string `yaml:"path" json:"path"` Format codec.Format `yaml:"format" json:"format"` reader *transport.Reader `yaml:"-" json:"-"` writer *transport.Writer `yaml:"-" json:"-"` encoder codec.Encoder `yaml:"-" json:"-"` decoder codec.Decoder `yaml:"-" json:"-"` } func NewConfigFile() *ConfigFile { return &ConfigFile{ Format: codec.FormatYaml } } func NewConfigFileFromURI(u *url.URL) *ConfigFile { t := NewConfigFile() if u.Scheme == "file" { t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.Path)) } else { t.Path = filepath.Join(u.Hostname(), u.Path) } return t } func NewConfigFileSource(u *url.URL) *ConfigFile { t := NewConfigFileFromURI(u) t.reader,_ = transport.NewReader(u) contentType := codec.Format(t.reader.ContentType()) if contentType.Validate() == nil { if formatErr := t.Format.Set(t.reader.ContentType()); formatErr != nil { panic(formatErr) } } t.decoder = codec.NewDecoder(t.reader, t.Format) return t } func NewConfigFileTarget(u *url.URL) *ConfigFile { t := NewConfigFileFromURI(u) t.writer,_ = transport.NewWriter(u) contentType := codec.Format(t.writer.ContentType()) if contentType.Validate() == nil { if formatErr := t.Format.Set(t.writer.ContentType()); formatErr != nil { panic(formatErr) } } t.encoder = codec.NewEncoder(t.writer, t.Format) return t } func init() { ConfigSourceTypes.Register([]string{"file"}, func(u *url.URL) ConfigSource { return NewConfigFileSource(u) }) ConfigSourceTypes.Register([]string{"pb","pb.gz","json","json.gz","yaml","yml","yaml.gz","yml.gz"}, func(u *url.URL) ConfigSource { return NewConfigFileSource(u) }) ConfigTargetTypes.Register([]string{"file"}, func(u *url.URL) ConfigTarget { return NewConfigFileTarget(u) }) ConfigTargetTypes.Register([]string{"pb","pb.gz","json","json.gz","yaml","yml","yaml.gz","yml.gz"}, func(u *url.URL) ConfigTarget { return NewConfigFileTarget(u) }) } func (c *ConfigFile) Type() string { return "file" } func (c *ConfigFile) Extract(filter ConfigurationSelector) ([]*Document, error) { documents := make([]*Document, 0, 100) defer func() { c.reader.Close() }() slog.Info("Extract()", "documents", documents) index := 0 for { doc := NewDocument() e := c.decoder.Decode(doc) if errors.Is(e, io.EOF) { break } if e != nil { return documents, e } slog.Info("Extract()", "res", doc.ConfigBlocks[0].Values) if validationErr := doc.Validate(); validationErr != nil { return documents, validationErr } documents = append(documents, doc) index++ } return documents, nil } func (c *ConfigFile) EmitResources(documents []*Document, filter ConfigurationSelector) (error) { defer func() { c.encoder.Close() c.writer.Close() }() for _, doc := range documents { emitDoc := NewDocument() if validationErr := doc.Validate(); validationErr != nil { return validationErr } for _, block := range doc.Filter(filter) { emitDoc.ConfigBlocks = append(emitDoc.ConfigBlocks, *block) } slog.Info("EmitResources", "doctarget", c, "encoder", c.encoder, "emit", emitDoc) if documentErr := c.encoder.Encode(emitDoc); documentErr != nil { slog.Info("EmitResources", "err", documentErr) return documentErr } } return nil } func (c *ConfigFile) Close() (error) { return nil }