diff --git a/global/global.go b/global/global.go index f2916d5..f7a1081 100644 --- a/global/global.go +++ b/global/global.go @@ -7,6 +7,18 @@ import ( "time" ) +var MimeTypes = map[string]string{ + "css": "text/css; charset=utf-8", + "png": "image/png", + "jpg": "image/jpg", + "webp": "image/webp", + "html": "text/html", + "asc": "text/plain", + "pub": "text/plain", + "txt": "text/plain", + "js": "application/javascript", +} + var LAST_MODIFIED = time.Now() func IsModified(req *http.Request, last_modified time.Time) bool { @@ -23,23 +35,23 @@ func IsModified(req *http.Request, last_modified time.Time) bool { return false } -type loggingResponseWriter struct { +type LoggingResponseWriter struct { http.ResponseWriter - code int + Code int } -func (lw *loggingResponseWriter) WriteHeader(code int) { - lw.code = code - lw.ResponseWriter.WriteHeader(code) +func (lrw *LoggingResponseWriter) WriteHeader(code int) { + lrw.Code = code + lrw.ResponseWriter.WriteHeader(code) } func HTTPLog(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() - lw := loggingResponseWriter{w, http.StatusOK} + lrw := LoggingResponseWriter{w, http.StatusOK} - next.ServeHTTP(&lw, r) + next.ServeHTTP(&lrw, r) after := time.Now() difference := (after.Nanosecond() - start.Nanosecond()) / 1_000_000 @@ -52,7 +64,7 @@ func HTTPLog(next http.Handler) http.Handler { after.Format(time.UnixDate), r.Method, r.URL.Path, - lw.code, + lrw.Code, elapsed, r.Header["User-Agent"][0]) }) diff --git a/main.go b/main.go index 5ac2ce9..5758d45 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,8 @@ import ( "html/template" "log" "net/http" - "path/filepath" + "os" + "path/filepath" "arimelody.me/arimelody.me/api/v1/admin" "arimelody.me/arimelody.me/api/v1/music" @@ -14,41 +15,6 @@ import ( const DEFAULT_PORT int = 8080 -// func handle_music(res http.ResponseWriter, req *http.Request, root *template.Template) int { -// if !global.IsModified(req, global.LAST_MODIFIED) { -// res.WriteHeader(304) -// return 304 -// } -// -// music_template := template.Must(root.ParseFiles("views/music.html")) -// err := music_template.Execute(res, music.Releases) -// if err != nil { -// http.Error(res, err.Error(), http.StatusInternalServerError) -// return 500 -// } -// return 200 -// } - -// func handle_music_gateway(res http.ResponseWriter, req *http.Request, root *template.Template) int { -// if !global.IsModified(req, global.LAST_MODIFIED) { -// res.WriteHeader(304) -// return 304 -// } -// -// id := req.URL.Path[len("/music/"):] -// release, err := music.GetRelease(id) -// if err != nil { -// return handle_not_found(res, req, root) -// } -// gateway_template := template.Must(root.ParseFiles("views/music-gateway.html")) -// err = gateway_template.Execute(res, release) -// if err != nil { -// http.Error(res, err.Error(), http.StatusInternalServerError) -// return 500 -// } -// return 200 -// } - func main() { db := InitDatabase() defer db.Close() @@ -66,23 +32,99 @@ func main() { } mux := http.NewServeMux() - + mux.Handle("/api/v1/admin/", global.HTTPLog(http.StripPrefix("/api/v1/admin", admin.Handler()))) - mux.Handle("/", http.FileServer(http.Dir("./public"))) - // mux.Handle("/", global.HTTPLog(http.HandlerFunc(serveTemplate))) + + mux.Handle("/music/", global.HTTPLog(http.StripPrefix("/music", musicGatewayHandler()))) + mux.Handle("/music", global.HTTPLog(serveTemplate("music.html", music.Releases))) + + mux.Handle("/", global.HTTPLog(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" || r.URL.Path == "/index.html" { + serveTemplate("index.html", nil).ServeHTTP(w, r) + return + } + staticHandler().ServeHTTP(w, r) + }))) port := DEFAULT_PORT fmt.Printf("now serving at http://127.0.0.1:%d\n", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), mux)) } -func serveTemplate(w http.ResponseWriter, r *http.Request) { - lp_base := filepath.Join("views", "layout.html") - lp_header := filepath.Join("views", "header.html") - lp_footer := filepath.Join("views", "footer.html") - lp_prideflag := filepath.Join("views", "prideflag.html") - fp := filepath.Join("views", filepath.Clean(r.URL.Path)) +func staticHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + info, err := os.Stat(filepath.Join("public", filepath.Clean(r.URL.Path))) + // does the file exist? + if err != nil { + if os.IsNotExist(err) { + http.NotFound(w, r) + return + } + } - template, _ := template.ParseFiles(lp_base, lp_header, lp_footer, lp_prideflag, fp) - template.ExecuteTemplate(w, "layout", nil) + // is thjs a directory? (forbidden) + if info.IsDir() { + http.NotFound(w, r) + return + } + + http.FileServer(http.Dir("./public")).ServeHTTP(w, r) + }) +} + +func musicGatewayHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + id := r.URL.Path[1:] + release, err := music.GetRelease(id) + if err != nil { + http.NotFound(w, r) + return + } + + lrw := global.LoggingResponseWriter{w, http.StatusOK} + + serveTemplate("music-gateway.html", release).ServeHTTP(&lrw, r) + + if lrw.Code != http.StatusOK { + fmt.Printf("Error loading music gateway for %s\n", id) + return + } + }) +} + +func serveTemplate(page string, data any) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + lp_layout := filepath.Join("views", "layout.html") + lp_header := filepath.Join("views", "header.html") + lp_footer := filepath.Join("views", "footer.html") + lp_prideflag := filepath.Join("views", "prideflag.html") + fp := filepath.Join("views", filepath.Clean(page)) + + info, err := os.Stat(fp) + if err != nil { + if os.IsNotExist(err) { + http.NotFound(w, r) + return + } + } + + if info.IsDir() { + http.NotFound(w, r) + return + } + + template, err := template.ParseFiles(lp_layout, lp_header, lp_footer, lp_prideflag, fp) + if err != nil { + fmt.Printf("Error parsing template files: %s\n", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + + err = template.ExecuteTemplate(w, "layout.html", data) + if err != nil { + fmt.Printf("Error executing template: %s\n", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + }) }