diff options
| author | herkulessi <git@herkulessi.de> | 2025-08-20 20:13:09 +0200 |
|---|---|---|
| committer | herkulessi <git@herkulessi.de> | 2025-08-20 20:13:09 +0200 |
| commit | 32e7fe5f94eee7e08f048d1ead1e7e82f29c46d6 (patch) | |
| tree | bb93bfa26873ad55b51b12398e837bd2ea880b50 | |
Initial commit of libmkwebpage
| -rw-r--r-- | go.mod | 3 | ||||
| -rw-r--r-- | main.go | 101 | ||||
| -rw-r--r-- | static.go | 14 | ||||
| -rw-r--r-- | templates.go | 70 |
4 files changed, 188 insertions, 0 deletions
@@ -0,0 +1,3 @@ +module herkulessi.de/git/libmkwebpage + +go 1.24.6 @@ -0,0 +1,101 @@ +package libmkwebpage + +import ( + "fmt" + "net/http" + "net/http/cgi" + "os" +) + +type Webpage struct { + muxStatic *http.ServeMux + muxDynamic *http.ServeMux + muxInternal *http.ServeMux + templates templates + staticFilePrefix string +} + +type handler struct { + w *Webpage +} + +func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if _, pattern := h.w.muxInternal.Handler(r); pattern != "" { + h.w.muxInternal.ServeHTTP(w, r) + return + } + h.w.getHandler().ServeHTTP(w, r) +} + +func New() *Webpage { + webpage := Webpage{muxStatic: http.NewServeMux(), muxDynamic: http.NewServeMux(), muxInternal: http.NewServeMux()} + webpage.muxInternal.HandleFunc("/.libmkpage/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "/.libmkpage/") }) + return &webpage +} + +// See http.HandleFunc +func (w *Webpage) Handle(pattern string, handler func(http.ResponseWriter, *http.Request)) *Webpage { + return w.HandleDynamic(pattern, handler).HandleStatic(pattern, handler) +} + +// See http.HandleFunc, only executed in dynamic requests (i.e. in a dev setup) +func (w *Webpage) HandleDynamic(pattern string, handler func(http.ResponseWriter, *http.Request)) *Webpage { + w.muxDynamic.HandleFunc(pattern, handler) + return w +} + +// See http.HandleFunc, only executed in static requests (i.e. in a prod setup) +func (w *Webpage) HandleStatic(pattern string, handler func(http.ResponseWriter, *http.Request)) *Webpage { + w.muxStatic.HandleFunc(pattern, handler) + return w +} + +// See http.Handle +func (w *Webpage) Handler(pattern string, handler http.Handler) *Webpage { + return w.HandlerDynamic(pattern, handler).HandlerStatic(pattern, handler) +} + +// See http.Handle, only executed in dynamic requests (i.e. in a dev setup) +func (w *Webpage) HandlerDynamic(pattern string, handler http.Handler) *Webpage { + w.muxDynamic.Handle(pattern, handler) + return w +} + +// See http.Handle, only executed in static requests (i.e. in a prod setup) +func (w *Webpage) HandlerStatic(pattern string, handler http.Handler) *Webpage { + w.muxStatic.Handle(pattern, handler) + return w +} + +// Returns the proper Mux for the current Request based on the request type without the magic internal mux +func (w *Webpage) getHandler() http.Handler { + if w.isDynamic() { + return w.muxDynamic + } else { + return w.muxStatic + } +} + +// Returns a http.Handler capable of hosting the application. Useful for combining more than one webpage in one binary +func (w *Webpage) GetHandler() http.Handler { + return handler{w} +} + +func (w *Webpage) isDynamic() bool { + return os.Getenv("PATH_INFO") == "" +} +func (w *Webpage) isStatic() bool { + return !w.isDynamic() +} + +func (w *Webpage) Serve() { + if w.isDynamic() { + fmt.Println("Listening on [::]:8080") + panic(http.ListenAndServe(":8080", w.GetHandler())) + } + err := cgi.Serve(w.GetHandler()) + if err != nil { + panic(err) + } + os.Exit(0) +} diff --git a/static.go b/static.go new file mode 100644 index 0000000..04c0fe6 --- /dev/null +++ b/static.go @@ -0,0 +1,14 @@ +package libmkwebpage + +import ( + "embed" + "io/fs" + "net/http" +) + +func (w *Webpage) NewStaticFiles(pattern string, static embed.FS, dynamic fs.FS) *Webpage { + w.HandlerDynamic("GET "+pattern, http.FileServerFS(dynamic)) + w.HandlerStatic("GET "+pattern, http.FileServerFS(static)) + w.staticFilePrefix = pattern + return w +} diff --git a/templates.go b/templates.go new file mode 100644 index 0000000..00c1b31 --- /dev/null +++ b/templates.go @@ -0,0 +1,70 @@ +package libmkwebpage + +import ( + "bytes" + "embed" + "fmt" + "html/template" + "io/fs" + "net/http" +) + +type templates struct { + staticRoot embed.FS + dynamicRoot fs.FS + errorTemplate string + bindings template.FuncMap +} + +func (w *Webpage) getTemplateRoot() fs.FS { + if w.isDynamic() { + return w.templates.dynamicRoot + } + return w.templates.staticRoot +} + +func (w *Webpage) NewTemplates(static embed.FS, dynamic fs.FS) *Webpage { + w.templates = templates{staticRoot: static, dynamicRoot: dynamic, bindings: template.FuncMap{}} + return w +} +func (w *Webpage) SetErrorTemplate(path string) { + w.templates.errorTemplate = path +} +func (w *Webpage) Error(writer http.ResponseWriter, code int, err error) { + writer.WriteHeader(code) + if w.templates.errorTemplate == "" { + fmt.Fprintln(writer, err) + } +} +func (w *Webpage) InternalServerError(writer http.ResponseWriter, err error) { + w.Error(writer, http.StatusInternalServerError, err) +} +func (w *Webpage) BadRequest(writer http.ResponseWriter, err error) { + w.Error(writer, http.StatusInternalServerError, err) +} +func (w *Webpage) BindTemplateFunc(name string, fun any) *Webpage { + w.templates.bindings[name] = fun + return w +} + +func (w *Webpage) RenderTemplate(writer http.ResponseWriter, name string, data any) { + writer.Header().Set("Content-Type", "text/html; charset=utf-8") + tmpl, err := fs.ReadFile(w.getTemplateRoot(), "templates/"+name+".tmpl") + if err != nil { + panic(err) + } + if err := template.Must(template.New("templates/"+name+".tmpl").Funcs(w.templates.bindings).Parse(string(tmpl))).Execute(writer, data); err != nil { + panic(err) + } +} +func (w *Webpage) RenderTemplateToString(name string, data any) string { + buf := bytes.NewBuffer(nil) + tmpl, err := fs.ReadFile(w.getTemplateRoot(), "templates/"+name+".tmpl") + if err != nil { + panic(err) + } + if err := template.Must(template.New("templates/"+name+".tmpl").Funcs(w.templates.bindings).Parse(string(tmpl))).Execute(buf, data); err != nil { + panic(err) + } + return buf.String() +} |
