| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- package main
- import (
- "encoding/json"
- "errors"
- "fmt"
- "io/fs"
- "log"
- "os"
- "strings"
- "sync"
- )
- // siteConfig holds the settings in site.json. Every field is optional.
- type siteConfig struct {
- HomeText string `json:"homeText"` // text of the header link to the index
- DefaultAuthor string `json:"defaultAuthor"` // author of posts that don't name one
- RepoURL string `json:"repoURL"` // web address of the source repo, for commit links
- }
- // withDefaults fills in any setting that is missing or blank.
- func (c siteConfig) withDefaults() siteConfig {
- if strings.TrimSpace(c.HomeText) == "" {
- c.HomeText = "Home"
- }
- if strings.TrimSpace(c.RepoURL) == "" {
- c.RepoURL = "https://git.monoexp.com/bajdev/posts"
- }
- if strings.TrimSpace(c.DefaultAuthor) == "" {
- c.DefaultAuthor = "Claude"
- }
- return c
- }
- // configFile reads site.json and re-reads it when its size or modification
- // time changes. A missing file means all defaults; a broken file is logged
- // and the last good settings stay in use.
- type configFile struct {
- path string
- mu sync.Mutex
- sig string
- loaded bool
- cfg siteConfig
- }
- func newConfigFile(path string) *configFile {
- return &configFile{path: path, cfg: siteConfig{}.withDefaults()}
- }
- func (c *configFile) Get() siteConfig {
- c.mu.Lock()
- defer c.mu.Unlock()
- sig := "missing"
- info, err := os.Stat(c.path)
- switch {
- case err == nil:
- sig = fmt.Sprintf("%d %d", info.Size(), info.ModTime().UnixNano())
- case !errors.Is(err, fs.ErrNotExist):
- log.Printf("%s: %v; keeping previous settings", c.path, err)
- return c.cfg
- }
- if c.loaded && sig == c.sig {
- return c.cfg
- }
- c.sig, c.loaded = sig, true
- if sig == "missing" {
- c.cfg = siteConfig{}.withDefaults()
- return c.cfg
- }
- cfg, err := readConfig(c.path)
- if err != nil {
- log.Printf("%s: %v; keeping previous settings", c.path, err)
- return c.cfg
- }
- c.cfg = cfg
- return c.cfg
- }
- func readConfig(path string) (siteConfig, error) {
- f, err := os.Open(path)
- if err != nil {
- return siteConfig{}, err
- }
- defer f.Close()
- dec := json.NewDecoder(f)
- dec.DisallowUnknownFields() // catch typos in setting names
- var cfg siteConfig
- if err := dec.Decode(&cfg); err != nil {
- return siteConfig{}, err
- }
- return cfg.withDefaults(), nil
- }
|