2024-09-19 08:11:57 +00:00
|
|
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
|
|
|
|
|
|
|
package resource
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"path/filepath"
|
|
|
|
"decl/internal/data"
|
|
|
|
"decl/internal/folio"
|
2024-09-28 05:04:15 +00:00
|
|
|
"log/slog"
|
2024-11-10 18:24:06 +00:00
|
|
|
"errors"
|
2024-09-19 08:11:57 +00:00
|
|
|
)
|
|
|
|
|
2024-09-28 05:04:15 +00:00
|
|
|
type UriSchemeValidator func(scheme string) bool
|
2024-10-09 22:26:39 +00:00
|
|
|
type UriNormalize func() error
|
2024-09-28 05:04:15 +00:00
|
|
|
|
2024-09-19 08:11:57 +00:00
|
|
|
type Common struct {
|
2024-09-28 05:04:15 +00:00
|
|
|
SchemeCheck UriSchemeValidator `json:"-" yaml:"-"`
|
2024-10-09 22:26:39 +00:00
|
|
|
NormalizePath UriNormalize `json:"-" yaml:"-"`
|
2024-09-19 08:11:57 +00:00
|
|
|
includeQueryParamsInURI bool `json:"-" yaml:"-"`
|
|
|
|
resourceType TypeName `json:"-" yaml:"-"`
|
|
|
|
parsedURI *url.URL `json:"-" yaml:"-"`
|
|
|
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
2024-10-16 17:26:42 +00:00
|
|
|
absPath string `json:"-" yaml:"-"`
|
2024-09-19 08:11:57 +00:00
|
|
|
|
|
|
|
exttype string `json:"-" yaml:"-"`
|
|
|
|
fileext string `json:"-" yaml:"-"`
|
|
|
|
normalizePath bool `json:"-" yaml:"-"`
|
|
|
|
|
|
|
|
State string `json:"state,omitempty" yaml:"state,omitempty"`
|
|
|
|
config data.ConfigurationValueGetter
|
|
|
|
Resources data.ResourceMapper `json:"-" yaml:"-"`
|
2024-11-10 18:24:06 +00:00
|
|
|
Errors []error `json:"-" yaml:"-"`
|
2024-09-19 08:11:57 +00:00
|
|
|
}
|
|
|
|
|
2024-09-28 05:04:15 +00:00
|
|
|
func NewCommon(resourceType TypeName, includeQueryParams bool) *Common {
|
|
|
|
c := &Common{ includeQueryParamsInURI: includeQueryParams, resourceType: resourceType }
|
|
|
|
c.SchemeCheck = c.IsValidResourceScheme
|
2024-10-09 22:26:39 +00:00
|
|
|
c.NormalizePath = c.NormalizeFilePath
|
2024-09-28 05:04:15 +00:00
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) IsValidResourceScheme(scheme string) bool {
|
|
|
|
return c.Type() == scheme
|
2024-09-19 08:11:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) ContentType() string {
|
|
|
|
if c.parsedURI.Scheme != "file" {
|
|
|
|
return c.parsedURI.Scheme
|
|
|
|
}
|
|
|
|
return c.exttype
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) SetResourceMapper(resources data.ResourceMapper) {
|
|
|
|
c.Resources = resources
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) Clone() *Common {
|
|
|
|
return &Common {
|
2024-10-16 17:26:42 +00:00
|
|
|
SchemeCheck: c.SchemeCheck,
|
|
|
|
NormalizePath: c.NormalizePath,
|
|
|
|
includeQueryParamsInURI: c.includeQueryParamsInURI,
|
|
|
|
resourceType: c.resourceType,
|
2024-09-19 08:11:57 +00:00
|
|
|
parsedURI: c.parsedURI,
|
|
|
|
Path: c.Path,
|
2024-10-16 17:26:42 +00:00
|
|
|
absPath: c.absPath,
|
2024-09-19 08:11:57 +00:00
|
|
|
exttype: c.exttype,
|
|
|
|
fileext: c.fileext,
|
|
|
|
normalizePath: c.normalizePath,
|
|
|
|
State: c.State,
|
|
|
|
config: c.config,
|
|
|
|
Resources: c.Resources,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) PathNormalization(flag bool) {
|
|
|
|
c.normalizePath = flag
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) URIPath() string {
|
|
|
|
return c.Path
|
|
|
|
}
|
|
|
|
|
2024-10-16 17:26:42 +00:00
|
|
|
func (c *Common) URI() folio.URI {
|
2024-10-16 17:51:58 +00:00
|
|
|
slog.Info("Common.URI", "parsed", c.parsedURI)
|
2024-10-16 17:26:42 +00:00
|
|
|
return folio.URI(c.parsedURI.String())
|
2024-09-19 08:11:57 +00:00
|
|
|
}
|
|
|
|
|
2024-10-16 17:26:42 +00:00
|
|
|
func (c *Common) SetParsedURI(u data.URIParser) (err error) {
|
|
|
|
if u != nil {
|
2024-09-19 08:11:57 +00:00
|
|
|
|
2024-10-16 17:26:42 +00:00
|
|
|
slog.Info("Common.SetParsedURI()", "parsed", u, "uri", c)
|
2024-09-19 08:11:57 +00:00
|
|
|
|
2024-10-16 17:26:42 +00:00
|
|
|
c.parsedURI = u.URL()
|
|
|
|
|
|
|
|
c.exttype, c.fileext = u.Extension()
|
2024-09-28 05:04:15 +00:00
|
|
|
if c.SchemeCheck(c.parsedURI.Scheme) {
|
2024-09-19 08:11:57 +00:00
|
|
|
if c.includeQueryParamsInURI {
|
|
|
|
c.Path = filepath.Join(c.parsedURI.Hostname(), c.parsedURI.RequestURI())
|
|
|
|
} else {
|
|
|
|
c.Path = filepath.Join(c.parsedURI.Hostname(), c.parsedURI.Path)
|
|
|
|
}
|
2024-11-10 18:24:06 +00:00
|
|
|
if c.config != nil {
|
|
|
|
if prefixPath, configErr := c.config.GetValue("prefix"); configErr == nil {
|
|
|
|
c.Path = filepath.Join(prefixPath.(string), c.Path)
|
|
|
|
}
|
|
|
|
}
|
2024-10-16 17:26:42 +00:00
|
|
|
if c.absPath, err = filepath.Abs(c.Path); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2024-09-19 08:11:57 +00:00
|
|
|
if err = c.NormalizePath(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2024-10-16 17:26:42 +00:00
|
|
|
err = fmt.Errorf("%w: %s is not a %s resource, parsed: %t", ErrInvalidResourceURI, c.URI(), c.Type(), (u != nil))
|
2024-09-19 08:11:57 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) UseConfig(config data.ConfigurationValueGetter) {
|
|
|
|
c.config = config
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) ResolveId(ctx context.Context) string {
|
2024-10-16 17:26:42 +00:00
|
|
|
var err error
|
|
|
|
if c.absPath, err = filepath.Abs(c.Path); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if err = c.NormalizePath(); err != nil {
|
|
|
|
panic(err)
|
2024-09-19 08:11:57 +00:00
|
|
|
}
|
|
|
|
return c.Path
|
|
|
|
}
|
|
|
|
|
2024-10-16 17:26:42 +00:00
|
|
|
// Common path normalization for a file resource.
|
|
|
|
func (c *Common) NormalizeFilePath() (err error) {
|
2024-09-19 08:11:57 +00:00
|
|
|
if c.normalizePath {
|
2024-10-16 17:26:42 +00:00
|
|
|
c.Path = c.absPath
|
2024-09-19 08:11:57 +00:00
|
|
|
}
|
2024-10-16 17:26:42 +00:00
|
|
|
return
|
2024-09-19 08:11:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) Type() string { return string(c.resourceType) }
|
2024-11-10 18:24:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
// If a resource update has errors but the resource is not actually absent
|
|
|
|
func (c *Common) IsResourceInconsistent() (result bool) {
|
|
|
|
for _, err := range c.Errors {
|
|
|
|
if ! errors.Is(err, ErrResourceStateAbsent) {
|
|
|
|
result = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Common) AddError(err error) (error) {
|
|
|
|
if err != nil {
|
|
|
|
c.Errors = append(c.Errors, err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|