diff --git a/go.mod b/go.mod index 5375841..18fc7d5 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/gliderlabs/ssh v0.3.5 github.com/go-sql-driver/mysql v1.6.0 github.com/gorilla/csrf v1.7.1 - github.com/gorilla/mux v1.8.0 github.com/gorilla/sessions v1.2.1 github.com/gorilla/websocket v1.5.0 github.com/julienschmidt/httprouter v1.3.0 diff --git a/go.sum b/go.sum index 31e6ee8..cf131af 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,6 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gorilla/csrf v1.7.1 h1:Ir3o2c1/Uzj6FBxMlAUB6SivgVMy1ONXwYgXn+/aHPE= github.com/gorilla/csrf v1.7.1/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= @@ -99,6 +97,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/dis/component/server/cron/cron.go b/internal/dis/component/server/cron/cron.go index 36b2584..56f92f3 100644 --- a/internal/dis/component/server/cron/cron.go +++ b/internal/dis/component/server/cron/cron.go @@ -119,18 +119,18 @@ func (control *Cron) Start(ctx context.Context, signal <-chan struct{}) <-chan s run() zerolog.Ctx(ctx).Debug().Msg("Cron() beginnning scheduling") - timer := timex.NewTimer() + t := timex.NewTimer() + defer timex.ReleaseTimer(t) for { - timex.StopTimer(timer) - timer.Reset(control.Config.CronInterval) + timex.StopTimer(t) + t.Reset(control.Config.CronInterval) select { - case <-timer.C: + case <-t.C: zerolog.Ctx(ctx).Debug().Msg("Cron() timer fired") case <-signal: zerolog.Ctx(ctx).Debug().Msg("Cron() received signal") case <-ctx.Done(): - timex.StopTimer(timer) return } diff --git a/internal/dis/component/server/templating/base.go b/internal/dis/component/server/templating/base.go index 4ebffea..4247893 100644 --- a/internal/dis/component/server/templating/base.go +++ b/internal/dis/component/server/templating/base.go @@ -3,6 +3,7 @@ package templating import ( "context" _ "embed" + "encoding/json" "fmt" "html/template" "net/http" @@ -11,6 +12,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/pkg/httpx" "github.com/FAU-CDI/wisski-distillery/pkg/pools" + "github.com/FAU-CDI/wisski-distillery/pkg/timex" "github.com/gorilla/csrf" "github.com/rs/zerolog" ) @@ -30,8 +32,21 @@ func (tpl *Template[C]) Template() *template.Template { return baseTemplate } +// LazyContext is like the lazy context +func (tpl *Template[C]) LazyContext(r *http.Request, f func() (C, error), funcs ...FlagFunc) (ctx *tContext[C]) { + ctx = tpl.context(r, funcs...) + ctx.startLazy(f) + return ctx +} + // Context generates the context to pass to an instance of the template returned by Template. func (tpl *Template[C]) Context(r *http.Request, c C, funcs ...FlagFunc) (ctx *tContext[C]) { + ctx = tpl.context(r, funcs...) + ctx.start(c, nil) // setup the request + return ctx +} + +func (tpl *Template[C]) context(r *http.Request, funcs ...FlagFunc) (ctx *tContext[C]) { // create a new context ctx = new(tContext[C]) @@ -45,16 +60,9 @@ func (tpl *Template[C]) Context(r *http.Request, c C, funcs ...FlagFunc) (ctx *t // generate the rest of the options ctx.Runtime.Flags = ctx.Runtime.Flags.Apply(r, tpl.p.funcs...) ctx.Runtime.Flags = ctx.Runtime.Flags.Apply(r, funcs...) - - // if the context has a runtime flags embed, then set the field properly - if tpl.p.hasRuntimeFlagsEmbed { - reflect.ValueOf(&c).Elem(). - FieldByName(runtimeFlagsName). - Set(reflect.ValueOf(ctx.Runtime)) - } + ctx.updateEmbedded = tpl.p.hasRuntimeFlagsEmbed // the main template - ctx.cMain = c ctx.tMain = tpl.p.tpl // the footer template @@ -126,22 +134,62 @@ func (tw *Template[C]) HTMLHandlerWithFlags(f func(r *http.Request) (C, []FlagFu // Callers may not retain references beyond the invocation of the template. // Callers must not rely on the internal structure of this tContext. type tContext[C any] struct { - Runtime RuntimeFlags // underlying flags + Runtime RuntimeFlags // underlying flags + updateEmbedded bool // should we automatically update an embedded RuntimeFlags inside the context? ctx context.Context // underlying context for render // the main template and context - tMain *template.Template - cMain C + eMain chan error // are we done? + cWaiting bool + tMain *template.Template + cMain C // the footer template and context tFooter *template.Template cFooter RuntimeFlags } +func (ctx *tContext[C]) start(c C, err error) { + ctx.cMain = c + ctx.eMain = make(chan error, 1) + ctx.eMain <- err +} + +func (ctx *tContext[C]) startLazy(f func() (C, error)) { + ctx.eMain = make(chan error, 1) + go func() { + defer close(ctx.eMain) + + // compute the result, storing the error + var err error + ctx.cMain, err = f() + ctx.eMain <- err + }() +} + +const mainDelay = time.Second + // Main renders the main template. func (ctx *tContext[C]) Main() (template.HTML, error) { - return ctx.renderSafe("main", ctx.tMain, ctx.cMain) + timer := timex.NewTimer() + defer timex.ReleaseTimer(timer) + + timer.Reset(mainDelay) + select { + + case err := <-ctx.eMain: + // we received the result within the given time + // so we can render it immediatly + ctx.cWaiting = false + return ctx.doMain(err) + + case <-timer.C: + // the template is taking longer than expected. + // we should display a spinner, and do something later + ctx.cWaiting = true + return timeWait, nil + } } // Footer renders the footer template @@ -149,6 +197,52 @@ func (ctx *tContext[C]) Footer() (template.HTML, error) { return ctx.renderSafe("footer", ctx.tFooter, ctx.cFooter) } +const ( + timeWait = "Loading" + errUnknown = "An unknown error occured, see the server log for details. " +) + +func (ctx *tContext[C]) doMain(err error) (template.HTML, error) { + zerolog.Ctx(ctx.ctx).Info().Msg("doMain") + if err != nil { + zerolog.Ctx(ctx.ctx).Err(err).Msg("error lazy loading template") + return errUnknown, nil + } + + // if the context has a runtime flags embed, then set the field properly + if ctx.updateEmbedded { + reflect.ValueOf(&ctx.cMain).Elem(). + FieldByName(runtimeFlagsName). + Set(reflect.ValueOf(ctx.Runtime)) + } + + return ctx.renderSafe("main", ctx.tMain, ctx.cMain) +} + +func (ctx *tContext[C]) AfterBody() (template.HTML, error) { + zerolog.Ctx(ctx.ctx).Info().Msg("AfterBody()") + // everything was done already + if !ctx.cWaiting { + return "", nil + } + + // wait for the result to appear + res, err := ctx.doMain(<-ctx.eMain) + if err != nil { + return "", err + } + + str, err := json.Marshal(string(res)) + if err != nil { + return "", err + } + + fix := "" + + // hook that is called after the body is complete + return template.HTML(fix), nil +} + const renderSafeError = "Error displaying page. See server log for details. " func (ctx *tContext[C]) renderSafe(name string, t *template.Template, c any) (template.HTML, error) { @@ -170,7 +264,7 @@ func (ctx *tContext[C]) renderSafe(name string, t *template.Template, c any) (te Str("uri", ctx.Runtime.RequestURI). Str("name", name). Str("panic", fmt.Sprint(r)). - Msg("templating.Main(): template panic()ed") + Msg("renderSafe: template panic()ed") } }() diff --git a/internal/dis/component/server/templating/src/base.html b/internal/dis/component/server/templating/src/base.html index f026ad4..f7ecde1 100644 --- a/internal/dis/component/server/templating/src/base.html +++ b/internal/dis/component/server/templating/src/base.html @@ -12,7 +12,7 @@