mirror of
https://github.com/Theodor-Springmann-Stiftung/lenz-web.git
synced 2025-10-28 08:45:32 +00:00
BUGFIX: race condition in engine; index page controller
This commit is contained in:
11
controllers/index.go
Normal file
11
controllers/index.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/xmlmodels"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func GetIndex(fiber *fiber.Ctx) error {
|
||||
_ = xmlmodels.Get()
|
||||
return fiber.Render("/", nil)
|
||||
}
|
||||
@@ -4,10 +4,16 @@ import (
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/helpers/middleware"
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/server"
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/views"
|
||||
|
||||
"github.com/gofiber/fiber/v2/middleware/compress"
|
||||
)
|
||||
|
||||
const ASSETS_URL = "/assets"
|
||||
|
||||
func Register(server server.Server) {
|
||||
server.Server.Use(ASSETS_URL, compress.New(compress.Config{
|
||||
Level: compress.LevelBestSpeed,
|
||||
}))
|
||||
server.Server.Use(ASSETS_URL, middleware.StaticHandler(&views.StaticFS))
|
||||
server.Server.Get("/", GetIndex)
|
||||
}
|
||||
|
||||
@@ -1,63 +1,67 @@
|
||||
package functions
|
||||
|
||||
type Month struct {
|
||||
Full string
|
||||
Short string
|
||||
Number string
|
||||
No int
|
||||
}
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Weekday struct {
|
||||
Full string
|
||||
Short string
|
||||
No int
|
||||
Name string
|
||||
ShortName string
|
||||
Number int
|
||||
}
|
||||
|
||||
func (m Month) String() string {
|
||||
return m.Full
|
||||
type Month struct {
|
||||
Name string
|
||||
ShortName string
|
||||
Number int
|
||||
}
|
||||
|
||||
func (w Weekday) String() string {
|
||||
return w.Full
|
||||
var Months = []Month{
|
||||
{"Januar", "Jan", 1},
|
||||
{"Februar", "Feb", 2},
|
||||
{"März", "Mär", 3},
|
||||
{"April", "Apr", 4},
|
||||
{"Mai", "Mai", 5},
|
||||
{"Juni", "Jun", 6},
|
||||
{"Juli", "Jul", 7},
|
||||
{"August", "Aug", 8},
|
||||
{"September", "Sep", 9},
|
||||
{"Oktober", "Okt", 10},
|
||||
{"November", "Nov", 11},
|
||||
{"Dezember", "Dez", 12},
|
||||
{"N/A", "N/A", 0},
|
||||
}
|
||||
|
||||
var TRANSLM = []Month{
|
||||
{"NotAvailable", "NA", "0", 0},
|
||||
{"Januar", "Jan", "1", 1},
|
||||
{"Februar", "Feb", "2", 2},
|
||||
{"März", "Mär", "3", 3},
|
||||
{"April", "Apr", "4", 4},
|
||||
{"Mai", "Mai", "5", 5},
|
||||
{"Juni", "Jun", "6", 6},
|
||||
{"Juli", "Jul", "7", 7},
|
||||
{"August", "Aug", "8", 8},
|
||||
{"September", "Sep", "9", 9},
|
||||
{"Oktober", "Okt", "10", 10},
|
||||
{"November", "Nov", "11", 11},
|
||||
{"Dezember", "Dez", "12", 12},
|
||||
}
|
||||
|
||||
var TRANSLD = []Weekday{
|
||||
{"NotAvailable", "NA", 0},
|
||||
var Weekdays = []Weekday{
|
||||
{"Sonntag", "So", 0},
|
||||
{"Montag", "Mo", 1},
|
||||
{"Dienstag", "Di", 2},
|
||||
{"Mittwoch", "Mi", 3},
|
||||
{"Donnerstag", "Do", 4},
|
||||
{"Freitag", "Fr", 5},
|
||||
{"Samstag", "Sa", 6},
|
||||
{"Sonntag", "So", 7},
|
||||
{"N/A", "N/A", 7},
|
||||
}
|
||||
|
||||
func MonthName(i int) Month {
|
||||
if i > 12 || i < 1 {
|
||||
return TRANSLM[0]
|
||||
}
|
||||
return TRANSLM[i]
|
||||
func Today() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
func WeekdayName(i int) Weekday {
|
||||
if i > 7 || i < 1 {
|
||||
return TRANSLD[0]
|
||||
func GetMonth(month any) Month {
|
||||
if val, ok := month.(int); ok {
|
||||
val -= 1
|
||||
if val < 0 || val > 11 {
|
||||
val = 12
|
||||
}
|
||||
return Months[val]
|
||||
}
|
||||
return TRANSLD[i]
|
||||
|
||||
if val, ok := month.(time.Time); ok {
|
||||
m := val.Month() - 1
|
||||
return Months[m]
|
||||
}
|
||||
|
||||
fmt.Println("Invalid month value", month)
|
||||
return Months[12]
|
||||
}
|
||||
|
||||
6
lenz.go
6
lenz.go
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/config"
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/controllers"
|
||||
gitprovider "github.com/Theodor-Springmann-Stiftung/lenz-web/git"
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/server"
|
||||
"github.com/Theodor-Springmann-Stiftung/lenz-web/templating"
|
||||
@@ -41,7 +42,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// INFO: the lib, engine and storage objects passed to the server are not made to be recreated.
|
||||
// INFO: the lib, engine and storage objects passed to the server should never be recreated.
|
||||
err = xmlmodels.New(dir, commit.Hash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -57,6 +58,7 @@ func main() {
|
||||
}
|
||||
|
||||
server := server.New(engine, storage, cfg.Debug)
|
||||
controllers.Register(server)
|
||||
|
||||
server.Start(cfg.Address + ":" + cfg.Port)
|
||||
}
|
||||
@@ -92,11 +94,13 @@ func SetupReloadWatcher(storage fiber.Storage, engine *templating.Engine) {
|
||||
}
|
||||
|
||||
func ResetFunction(storage fiber.Storage, engine *templating.Engine) {
|
||||
slog.Debug("Resetting storage and reloading engine")
|
||||
storage.Reset()
|
||||
engine.Reload()
|
||||
}
|
||||
|
||||
func RefreshFunction(storage fiber.Storage, engine *templating.Engine) {
|
||||
slog.Debug("Resetting storage and sending refresh signal")
|
||||
storage.Reset()
|
||||
engine.Refresh()
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func (e *Engine) setDebugData() {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
e.debug = true
|
||||
e.GlobalData["debug"] = true
|
||||
e.GlobalData["isDev"] = true
|
||||
e.GlobalData["debugport"] = WS_SERVER
|
||||
}
|
||||
|
||||
@@ -121,6 +121,8 @@ func (e *Engine) funcs() error {
|
||||
|
||||
// Passing HTML
|
||||
e.AddFunc("Safe", functions.Safe)
|
||||
e.AddFunc("Today", functions.Today)
|
||||
e.AddFunc("GetMonth", functions.GetMonth)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -159,9 +161,9 @@ func (e *Engine) Load() error {
|
||||
|
||||
func (e *Engine) Reload() {
|
||||
e.regmu.Lock()
|
||||
defer e.regmu.Unlock()
|
||||
e.LayoutRegistry = e.LayoutRegistry.Reset()
|
||||
e.TemplateRegistry = e.TemplateRegistry.Reset()
|
||||
e.regmu.Unlock()
|
||||
e.Load()
|
||||
}
|
||||
|
||||
|
||||
3104
views/assets/fonts/remixicon.css
Normal file
3104
views/assets/fonts/remixicon.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
views/assets/fonts/remixicon.eot
Normal file
BIN
views/assets/fonts/remixicon.eot
Normal file
Binary file not shown.
1
views/assets/fonts/remixicon.glyph.json
Normal file
1
views/assets/fonts/remixicon.glyph.json
Normal file
File diff suppressed because one or more lines are too long
3106
views/assets/fonts/remixicon.less
Normal file
3106
views/assets/fonts/remixicon.less
Normal file
File diff suppressed because it is too large
Load Diff
3088
views/assets/fonts/remixicon.module.less
Normal file
3088
views/assets/fonts/remixicon.module.less
Normal file
File diff suppressed because it is too large
Load Diff
6145
views/assets/fonts/remixicon.scss
Normal file
6145
views/assets/fonts/remixicon.scss
Normal file
File diff suppressed because it is too large
Load Diff
3075
views/assets/fonts/remixicon.styl
Normal file
3075
views/assets/fonts/remixicon.styl
Normal file
File diff suppressed because it is too large
Load Diff
9196
views/assets/fonts/remixicon.svg
Normal file
9196
views/assets/fonts/remixicon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 2.6 MiB |
11
views/assets/fonts/remixicon.symbol.svg
Normal file
11
views/assets/fonts/remixicon.symbol.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 1.7 MiB |
BIN
views/assets/fonts/remixicon.ttf
Normal file
BIN
views/assets/fonts/remixicon.ttf
Normal file
Binary file not shown.
BIN
views/assets/fonts/remixicon.woff
Normal file
BIN
views/assets/fonts/remixicon.woff
Normal file
Binary file not shown.
BIN
views/assets/fonts/remixicon.woff2
Normal file
BIN
views/assets/fonts/remixicon.woff2
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -10,13 +10,13 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>{{- .site.title }} – ein Projekt der</span>
|
||||
<span>{{- .title }} – ein Projekt der</span>
|
||||
<a href="https://theodor-springmann-stiftung.de">Theodor Springmann Stiftung</a>
|
||||
<span>·</span>
|
||||
<a href="/datenschutz/">Impressum & Datenschutz</a>
|
||||
<span>·</span>
|
||||
<i class="ri-code-line"></i>
|
||||
<a href="https://github.com/Theodor-Springmann-Stiftung/musenalm">Code</a>
|
||||
<a href="https://github.com/Theodor-Springmann-Stiftung/lenz-web">Code</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
52
views/layouts/components/_globalscripts.gohtml
Normal file
52
views/layouts/components/_globalscripts.gohtml
Normal file
@@ -0,0 +1,52 @@
|
||||
<!-- Mark selected anchor location for CSS & Assistive Technology -->
|
||||
<script type="module">
|
||||
const hash = window.location.hash;
|
||||
if (hash) {
|
||||
const stripped = hash.slice(1);
|
||||
const element = document.getElementById(stripped);
|
||||
if (element) {
|
||||
element.setAttribute("aria-current", "location");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{{ if .isDev }}
|
||||
<!-- Reload script for development -->
|
||||
<script type="module">
|
||||
(function () {
|
||||
let relto = -1;
|
||||
const scheme = location.protocol === "https:" ? "wss" : "ws";
|
||||
// Hardcode port 9000 here:
|
||||
const url = scheme + "://" + location.hostname + ":9000/pb/reload";
|
||||
|
||||
function connect() {
|
||||
const socket = new WebSocket(url);
|
||||
|
||||
socket.addEventListener("open", function () {
|
||||
console.log("Reload socket connected (port 9000).");
|
||||
});
|
||||
|
||||
socket.addEventListener("message", function (evt) {
|
||||
if (evt.data === "reload") {
|
||||
console.log("Received reload signal. Reloading...");
|
||||
if (relto !== -1) clearTimeout(relto);
|
||||
relto = setTimeout(() => location.reload(), 0);
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener("close", function () {
|
||||
console.log("Reload socket closed. Reconnecting in 3 seconds...");
|
||||
setTimeout(connect, 3000);
|
||||
});
|
||||
|
||||
socket.addEventListener("error", function (err) {
|
||||
console.error("Reload socket error:", err);
|
||||
// We'll let onclose handle reconnection.
|
||||
});
|
||||
}
|
||||
|
||||
// Initiate the first connection attempt.
|
||||
connect();
|
||||
})();
|
||||
</script>
|
||||
{{ end }}
|
||||
@@ -21,14 +21,8 @@
|
||||
{{ end }}
|
||||
|
||||
|
||||
<script src="/assets/js/alpine.min.js" defer></script>
|
||||
<script src="/assets/js/htmx.min.js" defer></script>
|
||||
<script src="/assets/js/htmx-response-targets.js" defer></script>
|
||||
<script src="/assets/js/mark.min.js" defer></script>
|
||||
|
||||
<script type="module" src="/assets/scripts.js"></script>
|
||||
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" type="text/css" href="/assets/css/fonts.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
||||
|
||||
<script type="module">
|
||||
@@ -67,17 +61,10 @@
|
||||
<!-- Default scripts... -->
|
||||
{{ end }}
|
||||
|
||||
{{ block "_globalscripts" . }}
|
||||
<!-- Default global scripts... -->
|
||||
{{ end }}
|
||||
|
||||
<script type="module">
|
||||
const hash = window.location.hash;
|
||||
if (hash) {
|
||||
const stripped = hash.slice(1);
|
||||
const element = document.getElementById(stripped);
|
||||
if (element) {
|
||||
element.setAttribute("aria-current", "location");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
3104
views/public/fonts/remixicon.css
Normal file
3104
views/public/fonts/remixicon.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
views/public/fonts/remixicon.eot
Normal file
BIN
views/public/fonts/remixicon.eot
Normal file
Binary file not shown.
1
views/public/fonts/remixicon.glyph.json
Normal file
1
views/public/fonts/remixicon.glyph.json
Normal file
File diff suppressed because one or more lines are too long
3106
views/public/fonts/remixicon.less
Normal file
3106
views/public/fonts/remixicon.less
Normal file
File diff suppressed because it is too large
Load Diff
3088
views/public/fonts/remixicon.module.less
Normal file
3088
views/public/fonts/remixicon.module.less
Normal file
File diff suppressed because it is too large
Load Diff
6145
views/public/fonts/remixicon.scss
Normal file
6145
views/public/fonts/remixicon.scss
Normal file
File diff suppressed because it is too large
Load Diff
3075
views/public/fonts/remixicon.styl
Normal file
3075
views/public/fonts/remixicon.styl
Normal file
File diff suppressed because it is too large
Load Diff
9196
views/public/fonts/remixicon.svg
Normal file
9196
views/public/fonts/remixicon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 2.6 MiB |
11
views/public/fonts/remixicon.symbol.svg
Normal file
11
views/public/fonts/remixicon.symbol.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 1.7 MiB |
BIN
views/public/fonts/remixicon.ttf
Normal file
BIN
views/public/fonts/remixicon.ttf
Normal file
Binary file not shown.
BIN
views/public/fonts/remixicon.woff
Normal file
BIN
views/public/fonts/remixicon.woff
Normal file
Binary file not shown.
BIN
views/public/fonts/remixicon.woff2
Normal file
BIN
views/public/fonts/remixicon.woff2
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
Helo from body!
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// INFO: We import this so vite processes the stylesheet
|
||||
import "../public/css/fonts.css";
|
||||
import "./site.css";
|
||||
import "../public/js/alpine.min.js";
|
||||
import "../public/js/htmx.min.js";
|
||||
|
||||
const ATTR_XSLT_ONLOAD = "script[xslt-onload]";
|
||||
const ATTR_XSLT_TEMPLATE = "xslt-template";
|
||||
|
||||
@@ -40,7 +40,7 @@ func New(fn func()) (*Watcher, error) {
|
||||
reloadTimer.Stop()
|
||||
}
|
||||
reloadTimer = time.AfterFunc(WATCHER_DEBOUNCE, func() {
|
||||
slog.Debug("Changes detected, reloading templates...")
|
||||
slog.Debug("Changes detected...")
|
||||
fn()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func Iterate[T any](xmlData string, initialState T) iter.Seq2[*TokenResult[T], e
|
||||
decoder := xml.NewDecoder(strings.NewReader(xmlData))
|
||||
stack := []Element{}
|
||||
state := initialState
|
||||
return iter.Seq2[*TokenResult[T], error](func(yield func(*TokenResult[T], error) bool) {
|
||||
return func(yield func(*TokenResult[T], error) bool) {
|
||||
for {
|
||||
token, err := decoder.Token()
|
||||
if err == io.EOF {
|
||||
@@ -117,7 +117,7 @@ func Iterate[T any](xmlData string, initialState T) iter.Seq2[*TokenResult[T], e
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// mapAttributes converts xml.Attr to a map[string]string.
|
||||
|
||||
@@ -134,9 +134,8 @@ func (p *XMLParser[T]) addResolvable(item T) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *XMLParser[T]) ReverseLookup(item IXMLItem) []Resolved[T] {
|
||||
func (p *XMLParser[T]) ReverseLookup(item IXMLItem) (ret []Resolved[T]) {
|
||||
// INFO: this runs just once for the first key
|
||||
ret := make([]Resolved[T], 0)
|
||||
keys := item.Keys()
|
||||
|
||||
for _, key := range keys {
|
||||
@@ -146,17 +145,16 @@ func (p *XMLParser[T]) ReverseLookup(item IXMLItem) []Resolved[T] {
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
return
|
||||
}
|
||||
|
||||
func (a *XMLParser[T]) String() string {
|
||||
func (a *XMLParser[T]) String() (s string) {
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
var s string
|
||||
for _, item := range a.array {
|
||||
s += item.String()
|
||||
}
|
||||
return s
|
||||
return
|
||||
}
|
||||
|
||||
func (p *XMLParser[T]) Info(id string) ItemInfo {
|
||||
|
||||
Reference in New Issue
Block a user