diff options
author | Martin Fischer <martin@push-f.com> | 2025-04-13 18:04:19 +0200 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2025-04-13 23:18:01 +0200 |
commit | 96236c9d80cea2d6ba83591a7d08a8cc096fd8d3 (patch) | |
tree | 4410c6a84e1be55fece4c5d34ed9288034fec589 | |
parent | f1b0f9b6c9404cca0a5cd230279dd82254b18378 (diff) |
feat: enable reloading of law JSON files
-rw-r--r-- | lex-serve/main.go | 74 |
1 files changed, 50 insertions, 24 deletions
diff --git a/lex-serve/main.go b/lex-serve/main.go index ac67ad4..98cc403 100644 --- a/lex-serve/main.go +++ b/lex-serve/main.go @@ -10,7 +10,9 @@ import ( "net/http" "net/url" "os" + "path" "strings" + "sync" "github.com/BurntSushi/toml" ) @@ -33,7 +35,13 @@ func main() { os.Exit(1) } - var handler = handler{logger: log, domain: domain, lawsByCC: map[string]map[string]law{}} + lawsDir := os.Getenv("LAWS_DIR") + if lawsDir == "" { + log.Error("LAWS_DIR must be set") + os.Exit(1) + } + + var handler = handler{logger: log, domain: domain, lawsDir: lawsDir, lawsByCC: map[string]map[string]law{}} meta, err := toml.NewDecoder(bytes.NewReader(countriesTOML)).Decode(&handler.countries) if err != nil { log.Error("failed to parse countries.toml", Error(err)) @@ -44,30 +52,15 @@ func main() { os.Exit(1) } - lawFiles, err := os.ReadDir("laws") - if err != nil { - log.Error("failed to read laws/ directory", Error(err)) - os.Exit(1) - } - for _, file := range lawFiles { - text, err := os.ReadFile("laws/" + file.Name()) - if err != nil { - log.Error("failed to read file", Error(err), "path", "laws/"+file.Name()) - os.Exit(1) - } - var laws []law - err = json.Unmarshal([]byte(text), &laws) - if err != nil { - log.Error("failed to parse file", Error(err), "path", file.Name()) - os.Exit(1) - } - cc := strings.SplitN(file.Name(), ".", 2)[0] - handler.lawsByCC[cc] = map[string]law{} - for _, law := range laws { - if law.Redir != "" { - handler.lawsByCC[cc][law.Redir] = law - } + lawFiles, err := os.ReadDir(lawsDir) + if err == nil { + for _, file := range lawFiles { + cc := strings.SplitN(file.Name(), ".", 2)[0] + handler.loadLaws(cc) } + } else if !os.IsNotExist(err) { + log.Error("failed to read laws directory", Error(err), "path", lawsDir) + os.Exit(1) } http.HandleFunc("/", handler.handle) listener, err := net.Listen("unix", socketPath) @@ -94,10 +87,16 @@ type handler struct { logger *slog.Logger domain string countries map[string]country + lawsDir string lawsByCC map[string]map[string]law + lawsMu sync.RWMutex } func (h *handler) handle(w http.ResponseWriter, r *http.Request) { + if r.Host == "internal.invalid" { + h.loadLaws(r.URL.Query().Get("country")) + return + } if r.Host == h.domain { if r.URL.Path != "/" { w.WriteHeader(http.StatusNotFound) @@ -126,6 +125,8 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) { } key := strings.TrimLeft(r.URL.Path, "/") if len(key) > 0 { + h.lawsMu.RLock() + defer h.lawsMu.RUnlock() val, ok := h.lawsByCC[cc][key] if !ok { w.WriteHeader(http.StatusNotFound) @@ -149,6 +150,8 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) } } + h.lawsMu.RLock() + defer h.lawsMu.RUnlock() _, hasJSONLaws := h.lawsByCC[cc] var html bytes.Buffer err := tpl.ExecuteTemplate(&html, "search.html.tmpl", map[string]any{ @@ -166,6 +169,29 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) { } } +func (h *handler) loadLaws(country string) { + filePath := path.Join(h.lawsDir, country+".json") + text, err := os.ReadFile(filePath) + if err != nil { + h.logger.Error("failed to read file", Error(err), "path", filePath) + return + } + var laws []law + err = json.Unmarshal([]byte(text), &laws) + if err != nil { + h.logger.Error("failed to parse file", Error(err), "path", filePath) + return + } + h.lawsMu.Lock() + defer h.lawsMu.Unlock() + h.lawsByCC[country] = map[string]law{} + for _, law := range laws { + if law.Redir != "" { + h.lawsByCC[country][law.Redir] = law + } + } +} + type law struct { URL string Title string |