diff options
| author | mihna123 <mihailonvojinovic@gmail.com> | 2026-09-04 01:13:17 +0200 |
|---|---|---|
| committer | mihna123 <mihailonvojinovic@gmail.com> | 2026-09-04 01:13:17 +0200 |
| commit | 5907450d569c997809674a2abeec97ddf0afe4aa (patch) | |
| tree | 7bd5af677b14433b5c18879e08bb672c87e259e1 /internal | |
| parent | a57f4fcbcd7857286cff854f6d62285df7d098aa (diff) | |
| download | openstore-5907450d569c997809674a2abeec97ddf0afe4aa.tar.gz openstore-5907450d569c997809674a2abeec97ddf0afe4aa.zip | |
config: add config package and wire it into server and handlers
Replace the hardcoded server.Config with an ini-backed config package
that reads /etc/openstore/openstore.conf then the user's config file, so
user settings override system ones and both override the built-in
defaults. Missing files are ignored rather than fatal.
Move route registration into a handlers package that owns the templates
and builds a Page view model, which removes the server -> handlers
import cycle along with the setter-based context injection.
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/config/config.go | 73 | ||||
| -rw-r--r-- | internal/server/handlers/handlers.go | 25 | ||||
| -rw-r--r-- | internal/server/handlers/pages.go | 24 | ||||
| -rw-r--r-- | internal/server/server.go | 36 | ||||
| -rw-r--r-- | internal/server/server_test.go | 22 | ||||
| -rw-r--r-- | internal/web/templates/index.html | 6 |
6 files changed, 155 insertions, 31 deletions
diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..2be9dd6 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,73 @@ +package config + +import ( + "fmt" + "net/url" + "os" + "path/filepath" + + "gopkg.in/ini.v1" +) + +type Serve struct { + Addr string `ini:"addr"` +} + +type Instance struct { + Name string `ini:"name"` + ContactEmail string `ini:"contact-email"` + BaseURL string `ini:"base-url"` +} + +type Config struct { + Serve Serve `ini:"serve"` + Instance Instance `ini:"instance"` +} + +var systemConfigPath = "/etc/openstore/openstore.conf" + +func DefaultPath() (string, error) { + dir, err := os.UserConfigDir() + if err != nil { + return "", err + } + + return filepath.Join(dir, "openstore", "openstore.conf"), nil +} + +func Load(filename string) (*Config, error) { + cfg, err := ini.LoadSources(ini.LoadOptions{ + Loose: true, + KeyValueDelimiters: "=", + }, systemConfigPath, filename) + + if err != nil { + return nil, err + } + + config := &Config{ + Serve: Serve{ + Addr: ":3000", + }, + Instance: Instance{ + Name: "Openstore", + ContactEmail: "jane@doe.com", + BaseURL: "https://www.example.com", + }, + } + + err = cfg.MapTo(config) + if err != nil { + return nil, err + } + + u, err := url.Parse(config.Instance.BaseURL) + if err != nil || u.Host == "" || u.Scheme == "" { + return nil, fmt.Errorf( + "config: base-url must be an absolute url, got %s", + config.Instance.BaseURL, + ) + } + + return config, nil +} diff --git a/internal/server/handlers/handlers.go b/internal/server/handlers/handlers.go new file mode 100644 index 0000000..958ca30 --- /dev/null +++ b/internal/server/handlers/handlers.go @@ -0,0 +1,25 @@ +package handlers + +import ( + "html/template" + "net/http" + + "codeberg.org/mihna123/openstore/internal/config" + "codeberg.org/mihna123/openstore/internal/web" +) + +type Handler struct { + tmpl *template.Template + cfg *config.Config +} + +func Routes(conf *config.Config) *http.ServeMux { + handler := Handler{ + tmpl: template.Must(template.ParseFS(web.Files, "templates/*.html")), + cfg: conf, + } + mux := http.NewServeMux() + mux.HandleFunc("GET /{$}", handler.home) + + return mux +} diff --git a/internal/server/handlers/pages.go b/internal/server/handlers/pages.go new file mode 100644 index 0000000..8c5bfb5 --- /dev/null +++ b/internal/server/handlers/pages.go @@ -0,0 +1,24 @@ +package handlers + +import ( + "log/slog" + "net/http" + + "codeberg.org/mihna123/openstore/internal/config" +) + +type Page struct { + Lang string + Instance config.Instance + Data any +} + +func (h *Handler) home(w http.ResponseWriter, r *http.Request) { + page := Page{Lang: "en", Instance: h.cfg.Instance} + err := h.tmpl.ExecuteTemplate(w, "index.html", page) + + if err != nil { + slog.Error("render template", "err", err.Error()) + return + } +} diff --git a/internal/server/server.go b/internal/server/server.go index a444958..a2f2d45 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -5,55 +5,39 @@ import ( "net" "time" - "html/template" "net/http" - "codeberg.org/mihna123/openstore/internal/web" + "codeberg.org/mihna123/openstore/internal/config" + "codeberg.org/mihna123/openstore/internal/server/handlers" ) -type Config struct { - Name string -} - type Server struct { - config *Config - tmpl *template.Template + config *config.Config mux *http.ServeMux } -func (s *Server) routes() { - s.mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { - err := s.tmpl.ExecuteTemplate(w, "index.html", s.config) - - if err != nil { - slog.Error("render template", "err", err.Error()) - return - } - }) -} - -func (s *Server) Serve(addr string) error { +func (s *Server) Serve() error { httpSrv := &http.Server{ Handler: logRequests(s.mux), ReadHeaderTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } - ln, err := net.Listen("tcp", addr) + ln, err := net.Listen("tcp", s.config.Serve.Addr) if err != nil { return err } - slog.Info("listening", "name", s.config.Name, "addr", addr) + slog.Info("listening", "name", s.config.Instance.Name, "addr", s.config.Serve.Addr) return httpSrv.Serve(ln) } -func New(c *Config) *Server { +func New(c *config.Config) *Server { + mux := handlers.Routes(c) s := &Server{ config: c, - mux: http.NewServeMux(), - tmpl: template.Must(template.ParseFS(web.Files, "templates/*.html")), + mux: mux, } - s.routes() + return s } diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 7e6a748..aea434f 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -7,6 +7,8 @@ import ( "os" "strings" "testing" + + "codeberg.org/mihna123/openstore/internal/config" ) func TestMain(m *testing.M) { @@ -14,9 +16,23 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func newTestConfig(t *testing.T) *config.Config { + t.Helper() + return &config.Config{ + Serve: config.Serve{ + Addr: ":3000", + }, + Instance: config.Instance{ + Name: "TestStore", + ContactEmail: "test@email.com", + BaseURL: "https://example.com", + }, + } +} + func newTestServer(t *testing.T) *Server { t.Helper() - return New(&Config{Name: "test"}) + return New(newTestConfig(t)) } func TestRoutes(t *testing.T) { @@ -47,7 +63,9 @@ func TestRoutes(t *testing.T) { } func TestIndexRendersTemplate(t *testing.T) { - s := New(&Config{Name: "testname123"}) + cfg := newTestConfig(t) + cfg.Instance.Name = "testname123" + s := New(cfg) rec := httptest.NewRecorder() s.mux.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil)) diff --git a/internal/web/templates/index.html b/internal/web/templates/index.html index 54630e7..16ca1fe 100644 --- a/internal/web/templates/index.html +++ b/internal/web/templates/index.html @@ -3,11 +3,11 @@ <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> - <title>{{ .Name }}</title> - <link href="css/style.css" rel="stylesheet" /> + <title>{{ .Instance.Name }}</title> + <link href="/css/style.css" rel="stylesheet" /> </head> <body> - <h1>Welcome to {{ .Name }}!</h1> + <h1>Welcome to {{ .Instance.Name }}!</h1> <p>Work in progress...</p> </body> </html> |
