soju/config/config.go

118 lines
2.3 KiB
Go
Raw Normal View History

2020-02-18 13:10:23 +00:00
package config
import (
"bufio"
"fmt"
"io"
"os"
"github.com/google/shlex"
2020-02-18 13:10:23 +00:00
)
type TLS struct {
CertPath, KeyPath string
}
type Server struct {
Listen []string
Hostname string
TLS *TLS
SQLDriver string
SQLSource string
LogPath string
HTTPOrigins []string
2020-02-18 13:10:23 +00:00
}
func Defaults() *Server {
hostname, err := os.Hostname()
if err != nil {
hostname = "localhost"
}
return &Server{
Hostname: hostname,
SQLDriver: "sqlite3",
2020-03-13 17:13:03 +00:00
SQLSource: "soju.db",
2020-02-18 13:10:23 +00:00
}
}
func Load(path string) (*Server, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return Parse(f)
}
func Parse(r io.Reader) (*Server, error) {
scanner := bufio.NewScanner(r)
var directives []directive
for scanner.Scan() {
words, err := shlex.Split(scanner.Text())
if err != nil {
return nil, fmt.Errorf("failed to parse config file: %v", err)
} else if len(words) == 0 {
continue
}
name, params := words[0], words[1:]
directives = append(directives, directive{name, params})
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("failed to read config file: %v", err)
2020-02-18 13:10:23 +00:00
}
srv := Defaults()
for _, d := range directives {
switch d.Name {
case "listen":
var uri string
if err := d.parseParams(&uri); err != nil {
2020-02-18 13:10:23 +00:00
return nil, err
}
srv.Listen = append(srv.Listen, uri)
2020-02-18 13:10:23 +00:00
case "hostname":
if err := d.parseParams(&srv.Hostname); err != nil {
return nil, err
}
case "tls":
tls := &TLS{}
if err := d.parseParams(&tls.CertPath, &tls.KeyPath); err != nil {
return nil, err
}
srv.TLS = tls
case "sql":
if err := d.parseParams(&srv.SQLDriver, &srv.SQLSource); err != nil {
return nil, err
}
case "log":
if err := d.parseParams(&srv.LogPath); err != nil {
return nil, err
}
case "http-origin":
srv.HTTPOrigins = append(srv.HTTPOrigins, d.Params...)
2020-02-18 13:10:23 +00:00
default:
return nil, fmt.Errorf("unknown directive %q", d.Name)
}
}
return srv, nil
}
type directive struct {
Name string
Params []string
}
func (d *directive) parseParams(out ...*string) error {
if len(d.Params) != len(out) {
return fmt.Errorf("directive %q has wrong number of parameters: expected %v, got %v", d.Name, len(out), len(d.Params))
}
for i := range out {
*out[i] = d.Params[i]
}
return nil
}