sophuwu.site > myweb
added bbolt database http file server for media
added error page
sophuwu sophie@skisiel.com
Wed, 11 Dec 2024 05:31:19 +0100
commit

f5402b22680729161273f7b81cbae4a7d39840d9

parent

d2b5dc0bd5066297e5ab8888cebefb5dbed3f323

M main.gomain.go

@@ -3,6 +3,7 @@

import ( "context" "errors" + "fmt" "golang.org/x/sys/unix" "log" "net/http"

@@ -21,11 +22,35 @@ }

return false } +var HttpErrs = map[int]string{ + 401: "Unauthorized: You must log in to access this page.", + 403: "Forbidden: You do not have permission to access this page.", + 404: "Not found: the requested page does not exist. Please check the URL and try again.", + 500: "Internal server error: the server encountered an error while processing your request. Please try again later.", +} + func HttpErr(w http.ResponseWriter, r *http.Request, code int) { - http.Error(w, http.StatusText(code), code) + w.WriteHeader(code) + var ErrTxt string + if t, ok := HttpErrs[code]; ok { + ErrTxt = t + } else { + ErrTxt = "An error occurred. Please try again later." + } + data := template.Data("An error occurred", fmt.Sprintf("%d: %s", code, ErrTxt)) + data.Set("ErrText", ErrTxt) + data.Set("ErrCode", code) + err := template.Use(w, r, "err", data) + if err != nil { + log.Printf("error writing error page: %v", err) + } } func HttpIndex(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + HttpErr(w, r, 404) + return + } d, err := GetPageData("index") if CheckHttpErr(err, w, r, 500) { return

@@ -34,20 +59,8 @@ err = template.Use(w, r, "index", d)

_ = CheckHttpErr(err, w, r, 500) } -type HttpHjk struct { - http.ResponseWriter - status int -} - -func HttpFS(path, fspath string) (string, http.HandlerFunc) { - fileServer := http.StripPrefix(path, http.FileServer(http.Dir(fspath))) - return path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - hijack := &HttpHjk{ResponseWriter: w} - fileServer.ServeHTTP(hijack, r) - if hijack.status >= 400 && hijack.status < 600 { - HttpErr(w, r, hijack.status) - } - }) +func HttpFS(path, fspath string) { + http.Handle(path, http.StripPrefix(path, http.FileServer(http.Dir(fspath)))) } func main() {

@@ -59,8 +72,9 @@ }

http.HandleFunc("/", HttpIndex) http.HandleFunc("/blog/", BlogHandler) - http.HandleFunc(HttpFS("/static/", config.StaticPath)) - http.HandleFunc(HttpFS("/media/", config.MediaPath)) + HttpFS("/static/", config.StaticPath) + http.HandleFunc("/media/", MediaHandler) + // HttpFS("/media/", config.MediaPath) server := http.Server{Addr: config.ListenAddr, Handler: nil} go func() {
A media.go

@@ -0,0 +1,62 @@

+package main + +import ( + "go.etcd.io/bbolt" + "mime" + "net/http" + "path/filepath" + "sophuwu.site/myweb/template" + "strings" +) + +type DBFile struct { + Name string + Size int +} + +func (f *DBFile) Valid() bool { + if f.Name == "" || strings.HasPrefix(f.Name, ".") || strings.HasPrefix(f.Name, "_") || f.Size == 0 { + return false + } + return true +} +func (f *DBFile) Set(name string, size int) { + f.Name = name + f.Size = size +} + +func MediaHandler(w http.ResponseWriter, r *http.Request) { + path := strings.TrimPrefix(r.URL.Path, "/media/") + var err error + if path == "" { + var list []DBFile + var t DBFile + err = DB.Bolt.View(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte("media")) + return b.ForEach(func(k, v []byte) error { + t.Set(string(k), len(v)) + if t.Valid() { + list = append(list, t) + } + return nil + }) + }) + if CheckHttpErr(err, w, r, 500) { + return + } + d := template.Data("/media/", "Directory listing for /media/") + d.Set("Files", list) + d.Set("NoFiles", len(list)) + err = template.Use(w, r, "filelist", d) + CheckHttpErr(err, w, r, 500) + return + } + var data []byte + data, err = DB.GetBytes("media", path) + if CheckHttpErr(err, w, r, 404) { + return + } + w.WriteHeader(200) + w.Header().Set("content-type", mime.TypeByExtension(filepath.Ext(path))) + w.Write(data) +}
M webhome/static/style_main.csswebhome/static/style_main.css

@@ -54,7 +54,16 @@ min-height: 100%;

height: auto; max-height: max-content; } - +footer { + padding: 0; + margin: 0; + display: block; + position: sticky; + width: 100%; + top: 100%; + transform: translateY(-50%); + background-color: inherit; +} header { padding: 0; margin: 0;

@@ -64,6 +73,7 @@ width: 100%;

top: 0; background-color: inherit; } + header > div { display: flex; flex-direction: row;

@@ -97,6 +107,15 @@ }

header nav { margin: 0 0 0 auto; } +.center { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex-wrap: wrap; + margin: 0; + padding: 0; +} hr { margin: 0;

@@ -104,8 +123,8 @@ padding: 0;

border: none; border-bottom-style: solid; border-bottom-width: 1px; - width: calc(100% + 1rlh); - transform: translateX(-0.5rlh); + width: calc(100% + 1rem); + transform: translateX(-0.5rem); } button:hover {
M webhome/templates/err.htmlwebhome/templates/err.html

@@ -4,15 +4,15 @@ {{ template "head" . }}

<body> {{ template "nav" . }} <main> - <h1>An Error Occurred</h1> - <h4>Code: {{ .Code }}</h4> - <p> - {{ .Text }} - </p> - <p> - If you believe this is an error, please contact <a href="mailto:{{ .Email }}">{{ .Email }}</a>. - </p> + <section class="center"> + <h1>{{ .ErrCode }}</h1> + <h3>{{ .ErrText }}</h3> + </section> </main> +<footer> + <hr> + <p>If this looks like a mistake, or the problem persists, please contact the administrator at <a href="mailto:{{ .Email }}">{{ .Email }}</a> </p> +</footer> </body> </html> {{ end }}
A webhome/templates/filelist.html

@@ -0,0 +1,30 @@

+{{ define "filelist" }} +<html lang="en"> +{{ template "head" . }} +<body> +{{ template "nav" . }} +<main> + <h2>{{ .Title }}</h2> + <p> + {{ .Description }} + </p> + <p> + {{ .NoFiles }} files found. + </p> + <hr> + <table> + <tr> + <td>Name</td> + <td>Size</td> + </tr> + {{- range .Files -}} + <tr> + <td><a href="{{- .Name -}}">{{- .Name -}}</a></td> + <td>{{- .Size -}}</td> + </tr> + {{ end }} + </table> +</main> +</body> +</html> +{{ end }}