templating: Rework timers
This commit is contained in:
parent
66eb13df30
commit
2d163a4dad
9 changed files with 232 additions and 46 deletions
|
|
@ -3,10 +3,14 @@ package httpx
|
|||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/timex"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const HTMLFlushInterval = time.Second / 10
|
||||
|
||||
// WriteHTML writes a html response of type T to w.
|
||||
// If an error occured, writes an error response instead.
|
||||
func WriteHTML[T any](result T, err error, template *template.Template, templateName string, w http.ResponseWriter, r *http.Request) (e error) {
|
||||
|
|
@ -17,17 +21,39 @@ func WriteHTML[T any](result T, err error, template *template.Template, template
|
|||
}
|
||||
}()
|
||||
|
||||
// create a synced respone writer
|
||||
sw := &SyncedResponseWriter{ResponseWriter: w}
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
// and regularly flush it until the end of the function
|
||||
go func() {
|
||||
timer := timex.NewTimer()
|
||||
defer timex.ReleaseTimer(timer)
|
||||
|
||||
for {
|
||||
timer.Reset(HTMLFlushInterval)
|
||||
select {
|
||||
case <-timer.C:
|
||||
sw.Flush()
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// intercept any errors
|
||||
if HTMLInterceptor.Intercept(w, r, err) {
|
||||
if HTMLInterceptor.Intercept(sw, r, err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// write out the response as html
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
sw.Header().Set("Content-Type", "text/html")
|
||||
sw.WriteHeader(http.StatusOK)
|
||||
|
||||
// minify html!
|
||||
minifier := MinifyHTMLWriter(w)
|
||||
minifier := MinifyHTMLWriter(sw)
|
||||
defer minifier.Close()
|
||||
|
||||
// and return the template
|
||||
|
|
|
|||
47
pkg/httpx/sync.go
Normal file
47
pkg/httpx/sync.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package httpx
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SyncedResponseWriter wraps a http ResponseWriter to syncronize all actions
|
||||
type SyncedResponseWriter struct {
|
||||
m sync.Mutex
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
func (rw *SyncedResponseWriter) Header() http.Header {
|
||||
rw.m.Lock()
|
||||
defer rw.m.Unlock()
|
||||
|
||||
return rw.ResponseWriter.Header()
|
||||
}
|
||||
|
||||
func (rw *SyncedResponseWriter) Write(data []byte) (int, error) {
|
||||
rw.m.Lock()
|
||||
defer rw.m.Unlock()
|
||||
|
||||
return rw.ResponseWriter.Write(data)
|
||||
}
|
||||
|
||||
func (rw *SyncedResponseWriter) WriteHeader(statusCode int) {
|
||||
rw.m.Lock()
|
||||
defer rw.m.Unlock()
|
||||
|
||||
rw.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
// Flush flushes any partial output to the underlying ResponseWriter.
|
||||
// If the wrapped ResponseWriter does not implement flush, the function performs no operation.
|
||||
func (rw *SyncedResponseWriter) Flush() {
|
||||
f, ok := rw.ResponseWriter.(http.Flusher)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
rw.m.Lock()
|
||||
defer rw.m.Unlock()
|
||||
|
||||
f.Flush()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue