jx/internal/folio/block.go

245 lines
6.0 KiB
Go
Raw Permalink Normal View History

2024-08-18 01:19:56 +00:00
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
package folio
import (
"context"
"encoding/json"
"fmt"
"io"
2024-09-19 07:57:26 +00:00
"net/url"
2024-08-18 01:19:56 +00:00
"strings"
"gopkg.in/yaml.v3"
"decl/internal/codec"
"decl/internal/data"
"decl/internal/schema"
)
type ConfigKey string
// Lookup a config value using block.key identifier (E.g. system.GOOS)
func (c ConfigKey) GetValue() (value any, err error) {
fields := strings.SplitN(string(c), ".", 2)
if configBlock, ok := DocumentRegistry.ConfigNameMap.Get(fields[0]); ok && len(fields) > 1 {
return configBlock.GetValue(fields[1])
} else {
return nil, fmt.Errorf("%w - %s", data.ErrUnknownConfigurationType, c)
}
}
func (c ConfigKey) Get() any {
if v, err := c.GetValue(); err == nil {
return v
}
return nil
}
func (c ConfigKey) GetStringSlice() []string {
if v, err := c.GetValue(); err == nil {
return v.([]string)
}
return nil
}
2024-08-18 01:19:56 +00:00
type BlockType struct {
Name string `json:"name" yaml:"name"`
Type TypeName `json:"type" yaml:"type"`
}
type Block struct {
Name string `json:"name" yaml:"name"`
Type TypeName `json:"type" yaml:"type"`
Values data.Configuration `json:"values" yaml:"values"`
ConfigurationTypes data.TypesRegistry[data.Configuration] `json:"-" yaml:"-"`
}
func NewBlock() *Block {
return &Block{ Type: "generic", ConfigurationTypes: DocumentRegistry.ConfigurationTypes }
}
func (b *Block) Clone() data.Block {
return &Block {
Type: b.Type,
Values: b.Values.Clone(),
}
}
func (b *Block) Load(docData []byte, f codec.Format) (err error) {
err = f.StringDecoder(string(docData)).Decode(b)
return
}
func (b *Block) LoadReader(r io.ReadCloser, f codec.Format) (err error) {
err = f.Decoder(r).Decode(b)
return
}
func (b *Block) LoadString(docData string, f codec.Format) (err error) {
err = f.StringDecoder(docData).Decode(b)
return
}
func (b *Block) LoadBlock(yamlBlock string) (err error) {
return b.LoadString(yamlBlock, codec.FormatYaml)
}
func (b *Block) JSON() ([]byte, error) {
var buf strings.Builder
err := codec.FormatJson.Serialize(b, &buf)
return []byte(buf.String()), err
}
func (b *Block) YAML() ([]byte, error) {
var buf strings.Builder
err := codec.FormatYaml.Serialize(b, &buf)
return []byte(buf.String()), err
}
func (b *Block) PB() ([]byte, error) {
var buf strings.Builder
err := codec.FormatProtoBuf.Serialize(b, &buf)
return []byte(buf.String()), err
}
func (b *Block) Validate() (err error) {
var blockJson []byte
if blockJson, err = b.JSON(); err == nil {
s := schema.New(fmt.Sprintf("%s-block", b.Type), schemaFiles) // XXX wrong schemaFiles
err = s.Validate(string(blockJson))
}
return
}
func (b *Block) NewConfiguration(uri *string) (err error) {
if b.ConfigurationTypes == nil {
panic(fmt.Errorf("Undefined type registry: unable to create new configuration %s", *uri))
}
if uri == nil {
b.Values, err = b.ConfigurationTypes.New(fmt.Sprintf("%s://", b.Type))
} else {
b.Values, err = b.ConfigurationTypes.New(*uri)
}
return
}
2024-09-19 07:57:26 +00:00
func (b *Block) NewConfigurationFromParsedURI(uri *url.URL) (err error) {
if uri == nil {
b.Values, err = b.ConfigurationTypes.New(fmt.Sprintf("%s://", b.Type))
} else {
b.Values, err = b.ConfigurationTypes.NewFromParsedURI(uri)
}
return
}
2024-08-18 01:19:56 +00:00
func (b *Block) GetValue(key string) (any, error) {
return b.Values.GetValue(key)
}
func (b *Block) Configuration() data.Configuration {
return b.Values
}
func (b *Block) ConfigurationType() data.TypeName {
return data.TypeName(b.Type)
}
func (b *Block) URI() string {
return b.Values.URI()
}
func (b *Block) SetURI(uri string) (err error) {
if b.Values == nil {
if err = b.NewConfiguration(&uri); err != nil {
return
}
}
if b.Values == nil {
return fmt.Errorf("%w - %s", data.ErrUnknownConfigurationType, uri)
}
b.Type = TypeName(b.Values.Type())
_,err = b.Values.Read(context.Background())
return
}
func (b *Block) SetParsedURI(uri data.URIParser) (err error) {
2024-09-19 07:57:26 +00:00
if b.Values == nil {
if err = b.NewConfigurationFromParsedURI(uri.URL()); err != nil {
2024-09-19 07:57:26 +00:00
return
}
}
if b.Values == nil {
return fmt.Errorf("%w - %s", data.ErrUnknownConfigurationType, uri)
}
b.Type = TypeName(b.Values.Type())
_,err = b.Values.Read(context.Background())
return
}
2024-08-18 01:19:56 +00:00
func (b *Block) UnmarshalValue(value *BlockType) error {
if b.ConfigurationTypes == nil {
panic(fmt.Errorf("Undefined type registry: unable to create new configuration %s", value.Type))
}
b.Name = value.Name
if value.Type == "" {
b.Type = "generic"
} else {
b.Type = value.Type
}
newConfig, configErr := b.ConfigurationTypes.New(fmt.Sprintf("%s://", b.Type))
if configErr != nil {
return configErr
}
b.Values = newConfig
return nil
}
func (b *Block) UnmarshalYAML(value *yaml.Node) error {
2024-09-19 07:57:26 +00:00
if b.ConfigurationTypes == nil {
b.ConfigurationTypes = DocumentRegistry.ConfigurationTypes
}
2024-08-18 01:19:56 +00:00
t := &BlockType{}
if unmarshalConfigurationTypeErr := value.Decode(t); unmarshalConfigurationTypeErr != nil {
return unmarshalConfigurationTypeErr
}
if err := b.UnmarshalValue(t); err != nil {
return err
}
configurationVals := struct {
Values yaml.Node `json:"values"`
}{}
if unmarshalValuesErr := value.Decode(&configurationVals); unmarshalValuesErr != nil {
return unmarshalValuesErr
}
if unmarshalConfigurationErr := configurationVals.Values.Decode(b.Values); unmarshalConfigurationErr != nil {
return unmarshalConfigurationErr
}
_, readErr := b.Values.Read(context.Background())
return readErr
}
func (b *Block) UnmarshalJSON(jsonData []byte) error {
2024-09-19 07:57:26 +00:00
if b.ConfigurationTypes == nil {
b.ConfigurationTypes = DocumentRegistry.ConfigurationTypes
}
2024-08-18 01:19:56 +00:00
t := &BlockType{}
if unmarshalConfigurationTypeErr := json.Unmarshal(jsonData, t); unmarshalConfigurationTypeErr != nil {
return unmarshalConfigurationTypeErr
}
if err := b.UnmarshalValue(t); err != nil {
return err
}
configurationVals := struct {
Values data.Configuration `json:"values"`
}{Values: b.Values}
if unmarshalValuesErr := json.Unmarshal(jsonData, &configurationVals); unmarshalValuesErr != nil {
return unmarshalValuesErr
}
_, readErr := b.Values.Read(context.Background())
return readErr
}