2023-08-21 00:26:22 +01:00
|
|
|
package postfix_config
|
|
|
|
|
|
|
|
import (
|
2023-08-22 13:38:01 +01:00
|
|
|
"errors"
|
2023-08-21 00:26:22 +01:00
|
|
|
"fmt"
|
2023-08-22 13:38:01 +01:00
|
|
|
commaListScanner "github.com/1f349/lotus/postfix-config/comma-list-scanner"
|
2023-08-21 00:26:22 +01:00
|
|
|
configParser "github.com/1f349/lotus/postfix-config/config-parser"
|
|
|
|
mapProvider "github.com/1f349/lotus/postfix-config/map-provider"
|
|
|
|
"io"
|
2023-08-22 13:38:01 +01:00
|
|
|
"path/filepath"
|
2023-08-21 00:26:22 +01:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Decoder struct {
|
2023-08-22 13:38:01 +01:00
|
|
|
r *configParser.ConfigParser
|
|
|
|
temp map[string]string
|
|
|
|
basePath string
|
2023-08-21 00:26:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewDecoder(r io.Reader) *Decoder {
|
|
|
|
return &Decoder{r: configParser.NewConfigParser(r)}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Decoder) Load() error {
|
|
|
|
for d.r.Scan() {
|
|
|
|
k, v := d.r.Pair()
|
2023-08-22 13:38:01 +01:00
|
|
|
d.temp[k] = v
|
|
|
|
}
|
|
|
|
if err := d.r.Err(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch d.value.ParseProvider(k) {
|
|
|
|
case "comma":
|
2023-08-21 00:26:22 +01:00
|
|
|
m := mapProvider.SequenceMapProvider{}
|
|
|
|
|
2023-08-22 13:38:01 +01:00
|
|
|
s := commaListScanner.NewCommaListScanner(strings.NewReader(v))
|
2023-08-21 00:26:22 +01:00
|
|
|
for s.Scan() {
|
|
|
|
a := s.Text()
|
|
|
|
println("a", a)
|
|
|
|
if strings.HasPrefix(a, "$") {
|
2023-08-22 13:38:01 +01:00
|
|
|
m = append(m, &mapProvider.Variable{Name: a[1:]})
|
|
|
|
continue
|
2023-08-21 00:26:22 +01:00
|
|
|
}
|
2023-08-22 13:38:01 +01:00
|
|
|
|
|
|
|
v2, err := d.createValue(a)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-08-21 00:26:22 +01:00
|
|
|
}
|
2023-08-22 13:38:01 +01:00
|
|
|
m = append(m, v2)
|
2023-08-21 00:26:22 +01:00
|
|
|
}
|
|
|
|
if err := s.Err(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-08-22 13:38:01 +01:00
|
|
|
d.value.SetKey(k, m)
|
|
|
|
case "union":
|
|
|
|
if !strings.HasPrefix(v, "unionmap:{") || !strings.HasSuffix(v, "}") {
|
|
|
|
return errors.New("key requires a union map")
|
|
|
|
}
|
|
|
|
v = v[len("unionmap:{") : len(v)-1]
|
|
|
|
|
|
|
|
m := mapProvider.SequenceMapProvider{}
|
|
|
|
s := commaListScanner.NewCommaListScanner(strings.NewReader(v))
|
|
|
|
for s.Scan() {
|
|
|
|
a := s.Text()
|
|
|
|
v2, err := d.createValue(a)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
m = append(m, v2)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("key '%s' has no defined parse provider", k)
|
2023-08-21 00:26:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return d.r.Err()
|
|
|
|
}
|
2023-08-22 13:38:01 +01:00
|
|
|
|
|
|
|
func (d *Decoder) createValue(a string) (mapProvider.MapProvider, error) {
|
|
|
|
n := strings.IndexByte(a, ':')
|
|
|
|
if n == -1 {
|
|
|
|
return nil, fmt.Errorf("missing prefix")
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace := a[:n]
|
|
|
|
value := a[n+1:]
|
|
|
|
switch namespace {
|
|
|
|
case "mysql":
|
|
|
|
if !filepath.IsAbs(value) {
|
|
|
|
value = filepath.Join(d.basePath, value)
|
|
|
|
}
|
|
|
|
provider, err := mapProvider.NewMySqlMapProvider(value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return provider, nil
|
|
|
|
case "hash":
|
|
|
|
if !filepath.IsAbs(value) {
|
|
|
|
value = filepath.Join(d.basePath, value)
|
|
|
|
}
|
|
|
|
provider, err := mapProvider.NewHashMapProvider(value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return provider, nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("invalid provider namespace")
|
|
|
|
}
|