summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--cmd/openstore/main.go17
-rw-r--r--go.mod2
-rw-r--r--go.sum20
-rw-r--r--internal/config/config.go73
-rw-r--r--internal/server/handlers/handlers.go25
-rw-r--r--internal/server/handlers/pages.go24
-rw-r--r--internal/server/server.go36
-rw-r--r--internal/server/server_test.go22
-rw-r--r--internal/web/templates/index.html6
10 files changed, 193 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ba2906d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+main
diff --git a/cmd/openstore/main.go b/cmd/openstore/main.go
index 65d7afb..48b2df0 100644
--- a/cmd/openstore/main.go
+++ b/cmd/openstore/main.go
@@ -4,14 +4,27 @@ import (
"log/slog"
"os"
+ "codeberg.org/mihna123/openstore/internal/config"
"codeberg.org/mihna123/openstore/internal/server"
)
func main() {
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
- conf := &server.Config{Name: "OpenStore"}
+
+ dir, err := config.DefaultPath()
+ if err != nil {
+ slog.Error("failed to open config file", "err", err)
+ os.Exit(1)
+ }
+
+ conf, err := config.Load(dir)
+ if err != nil {
+ slog.Error("config load failed", "err", err)
+ os.Exit(1)
+ }
+
s := server.New(conf)
- if err := s.Serve(":3000"); err != nil {
+ if err := s.Serve(); err != nil {
slog.Error("server failed", "err", err)
os.Exit(1)
}
diff --git a/go.mod b/go.mod
index 4c2f56c..37fa535 100644
--- a/go.mod
+++ b/go.mod
@@ -3,3 +3,5 @@ module codeberg.org/mihna123/openstore
go 1.25.0
require golang.org/x/crypto v0.55.0
+
+require gopkg.in/ini.v1 v1.67.3
diff --git a/go.sum b/go.sum
index a6e2343..90c607f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,22 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.67.3 h1:iM9Lhz5MRSGhHVGGwCuzG9KO8PoirCXj/m/qTmOJJQw=
+gopkg.in/ini.v1 v1.67.3/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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>