package config import ( "context" "fmt" "net" "os" "path" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/sethvargo/go-envconfig" "gopkg.in/yaml.v3" ) type Config struct { Dev bool `yaml:"dev"` HostName string `yaml:"hostname"` OwnerDid syntax.DID `yaml:"owner_did"` ListenHost string `yaml:"listen_host"` ListenPort string `yaml:"listen_port"` DataDir string `yaml:"data_dir"` RepoDir string `yaml:"repo_dir"` PlcUrl string `yaml:"plc_url"` JetstreamEndpoint string `yaml:"jetstream_endpoint"` AppviewEndpoint string `yaml:"appview_endpoint"` GitUserName string `yaml:"git_user_name"` GitUserEmail string `yaml:"git_user_email"` OAuth OAuthConfig } type OAuthConfig struct { CookieSecret string `env:"KNOT2_COOKIE_SECRET, default=00000000000000000000000000000000"` ClientSecret string `env:"KNOT2_OAUTH_CLIENT_SECRET"` ClientKid string `env:"KNOT2_OAUTH_CLIENT_KID"` } func (c *Config) Uri() string { // TODO: make port configurable if c.Dev { return "http://127.0.0.1:6444" } return "https://" + c.HostName } func (c *Config) ListenAddr() string { return net.JoinHostPort(c.ListenHost, c.ListenPort) } func (c *Config) DbPath() string { return path.Join(c.DataDir, "knot.db") } func (c *Config) GitMotdFilePath() string { return path.Join(c.DataDir, "motd") } func (c *Config) Validate() error { if c.HostName == "" { return fmt.Errorf("knot hostname cannot be empty") } if c.OwnerDid == "" { return fmt.Errorf("knot owner did cannot be empty") } return nil } func Load(ctx context.Context, path string) (Config, error) { // NOTE: yaml.v3 package doesn't support "default" struct tag cfg := Config{ Dev: true, ListenHost: "0.0.0.0", ListenPort: "5555", DataDir: "/home/git", RepoDir: "/home/git", PlcUrl: "https://plc.directory", JetstreamEndpoint: "wss://jetstream1.us-west.bsky.network/subscribe", AppviewEndpoint: "https://tangled.org", GitUserName: "Tangled", GitUserEmail: "noreply@tangled.org", } // load config from env vars err := envconfig.Process(ctx, &cfg.OAuth) if err != nil { return cfg, err } // load config from toml config file bytes, err := os.ReadFile(path) if err != nil { return cfg, err } if err := yaml.Unmarshal(bytes, &cfg); err != nil { return cfg, err } // validate the config if err = cfg.Validate(); err != nil { return cfg, err } return cfg, nil }