mirror of
https://github.com/Theodor-Springmann-Stiftung/lenz-web.git
synced 2026-03-21 05:45:32 +00:00
Started server
This commit is contained in:
46
:wq
Normal file
46
:wq
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/app"
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Debug {
|
||||||
|
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||||
|
}
|
||||||
|
|
||||||
|
application, err := app.New(cfg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Serve(application)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Serve(app *app.App) error {
|
||||||
|
server, err := server.NewServer(app)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
server.Start()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig() (app.Config, error) {
|
||||||
|
cp := app.NewConfigProvider([]string{"config.dev.json", "config.json"})
|
||||||
|
if err := cp.Read(); err != nil {
|
||||||
|
return app.Config{}, err
|
||||||
|
}
|
||||||
|
return *cp.Config, nil
|
||||||
|
}
|
||||||
63
app/app.go
63
app/app.go
@@ -1,7 +1,6 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -12,12 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
lib atomic.Pointer[xmlmodels.Library]
|
lib atomic.Pointer[xmlmodels.Library]
|
||||||
repo atomic.Pointer[git.Repo]
|
repo atomic.Pointer[git.Repo]
|
||||||
tmpl *template.Template
|
tmpl atomic.Pointer[*template.Template]
|
||||||
routes []Route
|
cfg Config
|
||||||
err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg Config) (*App, error) {
|
func New(cfg Config) (*App, error) {
|
||||||
@@ -37,39 +35,15 @@ func (a *App) Repo() *git.Repo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Templates() *template.Template {
|
func (a *App) Templates() *template.Template {
|
||||||
return a.tmpl
|
return *a.tmpl.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Routes() []Route {
|
func (a *App) Config() Config {
|
||||||
a.mu.Lock()
|
return a.cfg
|
||||||
defer a.mu.Unlock()
|
|
||||||
|
|
||||||
ret := make([]Route, len(a.routes))
|
|
||||||
copy(ret, a.routes)
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) RenderPath(path string) ([]byte, error) {
|
func (a *App) Pages() []Page {
|
||||||
a.mu.Lock()
|
return RegisteredPages()
|
||||||
var route *Route
|
|
||||||
for i := range a.routes {
|
|
||||||
if a.routes[i].Path == path {
|
|
||||||
r := a.routes[i]
|
|
||||||
route = &r
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.mu.Unlock()
|
|
||||||
|
|
||||||
if route == nil || route.page == nil {
|
|
||||||
return nil, fmt.Errorf("no route for path: %s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
model, err := route.page.Model(a, *route)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return route.page.Render(a, *route, model)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) init(cfg Config) error {
|
func (a *App) init(cfg Config) error {
|
||||||
@@ -103,15 +77,9 @@ func (a *App) init(cfg Config) error {
|
|||||||
|
|
||||||
a.repo.Store(repo)
|
a.repo.Store(repo)
|
||||||
a.lib.Store(lib)
|
a.lib.Store(lib)
|
||||||
a.tmpl = tmpl
|
a.tmpl.Store(&tmpl)
|
||||||
|
|
||||||
routes, err := discoverPages(a)
|
a.cfg = cfg
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
a.routes = routes
|
|
||||||
a.err = nil
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,12 +94,5 @@ func (a *App) RefreshLibrary(dir string, commit *git.Commit) (*xmlmodels.Library
|
|||||||
|
|
||||||
a.lib.Store(lib)
|
a.lib.Store(lib)
|
||||||
|
|
||||||
routes, err := discoverPages(a)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
a.routes = routes
|
|
||||||
a.err = nil
|
|
||||||
return lib, nil
|
return lib, nil
|
||||||
}
|
}
|
||||||
|
|||||||
13
app/pages.go
13
app/pages.go
@@ -1,7 +1,5 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Path string
|
Path string
|
||||||
Kind string
|
Kind string
|
||||||
@@ -12,28 +10,19 @@ type Route struct {
|
|||||||
type Page interface {
|
type Page interface {
|
||||||
Discover(app *App) ([]Route, error)
|
Discover(app *App) ([]Route, error)
|
||||||
Model(app *App, route Route) (map[string]any, error)
|
Model(app *App, route Route) (map[string]any, error)
|
||||||
Render(app *App, route Route, model map[string]any) ([]byte, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var pages []Page
|
||||||
pagesMu sync.RWMutex
|
|
||||||
pages []Page
|
|
||||||
)
|
|
||||||
|
|
||||||
func RegisterPage(page Page) {
|
func RegisterPage(page Page) {
|
||||||
if page == nil {
|
if page == nil {
|
||||||
panic("cannot register nil page")
|
panic("cannot register nil page")
|
||||||
}
|
}
|
||||||
|
|
||||||
pagesMu.Lock()
|
|
||||||
defer pagesMu.Unlock()
|
|
||||||
pages = append(pages, page)
|
pages = append(pages, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisteredPages() []Page {
|
func RegisteredPages() []Page {
|
||||||
pagesMu.RLock()
|
|
||||||
defer pagesMu.RUnlock()
|
|
||||||
|
|
||||||
ret := make([]Page, len(pages))
|
ret := make([]Page, len(pages))
|
||||||
copy(ret, pages)
|
copy(ret, pages)
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
30
lenz.go
30
lenz.go
@@ -1,13 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/app"
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/app"
|
||||||
_ "github.com/Theodor-Springmann-Stiftung/lenz-web/pages"
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/server"
|
||||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/templates"
|
|
||||||
"github.com/labstack/echo/v5"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -25,28 +22,19 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := echo.New()
|
err = Serve(application)
|
||||||
publicFS, err := fs.Sub(templates.PublicFS, "public")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
e.StaticFS("/public", publicFS)
|
}
|
||||||
|
|
||||||
for _, route := range application.Routes() {
|
func Serve(app *app.App) error {
|
||||||
routePath := route.Path
|
server, err := server.NewServer(app)
|
||||||
e.GET(routePath, func(c *echo.Context) error {
|
if err != nil {
|
||||||
out, err := application.RenderPath(routePath)
|
return err
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.HTMLBlob(200, out)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
addr := cfg.Address + ":" + cfg.Port
|
|
||||||
if err := e.Start(addr); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
server.Start()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfig() (app.Config, error) {
|
func GetConfig() (app.Config, error) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package pages
|
package pages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/app"
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,11 +21,3 @@ func (p HomePage) Model(a *app.App, route app.Route) (map[string]any, error) {
|
|||||||
"Message": "Template system is working.",
|
"Message": "Template system is working.",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p HomePage) Render(a *app.App, route app.Route, model map[string]any) ([]byte, error) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := a.Templates().ExecuteTemplate(&buf, "home", model); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|||||||
11
server/endpoints.go
Normal file
11
server/endpoints.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/templates"
|
||||||
|
"github.com/labstack/echo/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MapStatic(e *echo.Echo) {
|
||||||
|
// INFO: Static files here:
|
||||||
|
e.StaticFS("/public", templates.PublicFS)
|
||||||
|
}
|
||||||
36
server/server.go
Normal file
36
server/server.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/lenz-web/app"
|
||||||
|
"github.com/labstack/echo/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WARNING: this is not thread-safe. You can not write and read from the server at the same time!
|
||||||
|
type Server struct {
|
||||||
|
server *echo.Echo
|
||||||
|
cfg app.Config
|
||||||
|
tmpl *template.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(app *app.App) (*Server, error) {
|
||||||
|
s := &Server{
|
||||||
|
server: echo.New(),
|
||||||
|
cfg: app.Config(),
|
||||||
|
tmpl: app.Templates(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO: Endpoint mapping here:
|
||||||
|
MapStatic(s.server)
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() error {
|
||||||
|
addr := s.cfg.Address + ":" + s.cfg.Port
|
||||||
|
if err := s.server.Start(addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user