fixed prior merge conflic causing double'd embed, added readme parser with full markdown, added readme render to HTML, renamed filepath to fpath to use FilePath.Join for case insensitivity, fixed ident in html src (inline css), added readme css with proper accents
This commit is contained in:
parent
cf03c723d0
commit
245d6e0fa0
4 changed files with 270 additions and 133 deletions
185
main.go
185
main.go
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
|
|
@ -8,11 +9,15 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
_ "embed"
|
||||
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
)
|
||||
|
||||
//go:embed templates/dir.html
|
||||
|
|
@ -20,25 +25,25 @@ var dirTemplateSrc string
|
|||
|
||||
type (
|
||||
Directory struct {
|
||||
Name string
|
||||
Root bool
|
||||
Files []*File
|
||||
Name string
|
||||
Root bool
|
||||
Files []*File
|
||||
Readme template.HTML
|
||||
}
|
||||
|
||||
File struct {
|
||||
Name string
|
||||
URI string
|
||||
IsDir bool
|
||||
Size string
|
||||
Name string
|
||||
URI string
|
||||
IsDir bool
|
||||
Size string
|
||||
ModifiedDate string
|
||||
}
|
||||
)
|
||||
|
||||
//go:embed templates/dir.html
|
||||
var dirHTML string
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 { printHelp() }
|
||||
if len(os.Args) < 2 {
|
||||
printHelp()
|
||||
}
|
||||
|
||||
host := "127.0.0.1"
|
||||
port := 8080
|
||||
|
|
@ -47,7 +52,9 @@ func main() {
|
|||
filesDir := ""
|
||||
i := 1
|
||||
for {
|
||||
if i >= len(os.Args) { break }
|
||||
if i >= len(os.Args) {
|
||||
break
|
||||
}
|
||||
switch os.Args[i] {
|
||||
case "-h":
|
||||
fallthrough
|
||||
|
|
@ -55,7 +62,7 @@ func main() {
|
|||
printHelp()
|
||||
|
||||
case "--host":
|
||||
if i + 1 >= len(os.Args) {
|
||||
if i+1 >= len(os.Args) {
|
||||
fmt.Fprintf(os.Stderr, "fatal: --host argument cannot be empty\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
@ -63,7 +70,7 @@ func main() {
|
|||
host = os.Args[i]
|
||||
|
||||
case "--port":
|
||||
if i + 1 >= len(os.Args) {
|
||||
if i+1 >= len(os.Args) {
|
||||
fmt.Fprintf(os.Stderr, "fatal: --port argument cannot be empty\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
@ -76,14 +83,18 @@ func main() {
|
|||
}
|
||||
|
||||
case "--root":
|
||||
if i + 1 >= len(os.Args) {
|
||||
if i+1 >= len(os.Args) {
|
||||
fmt.Fprintf(os.Stderr, "fatal: --root argument cannot be empty\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
i++
|
||||
root = os.Args[i]
|
||||
if !strings.HasPrefix(root, "/") { root = "/" + root }
|
||||
if !strings.HasSuffix(root, "/") { root += "/" }
|
||||
if !strings.HasPrefix(root, "/") {
|
||||
root = "/" + root
|
||||
}
|
||||
if !strings.HasSuffix(root, "/") {
|
||||
root += "/"
|
||||
}
|
||||
|
||||
default:
|
||||
if len(filesDir) > 0 {
|
||||
|
|
@ -111,7 +122,9 @@ func main() {
|
|||
}
|
||||
|
||||
fmt.Printf("Now hosting \"%s\" at http://%s:%d", filesDir, host, port)
|
||||
if root != "/" { fmt.Printf("%s", root) }
|
||||
if root != "/" {
|
||||
fmt.Printf("%s", root)
|
||||
}
|
||||
fmt.Println(".")
|
||||
|
||||
http.ListenAndServe(fmt.Sprintf("%s:%d", host, port), HTTPLog(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -121,8 +134,8 @@ func main() {
|
|||
}
|
||||
isRoot := r.URL.Path == root
|
||||
|
||||
filepath := path.Join(filesDir, strings.TrimPrefix(r.URL.Path, root))
|
||||
info, err := os.Stat(filepath)
|
||||
fpath := path.Join(filesDir, strings.TrimPrefix(r.URL.Path, root))
|
||||
info, err := os.Stat(fpath)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
|
@ -135,7 +148,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
file, err := os.Open(filepath)
|
||||
file, err := os.Open(fpath)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
|
|
@ -144,7 +157,7 @@ func main() {
|
|||
defer func() {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to close file %s: %v\n", filepath, err)
|
||||
fmt.Fprintf(os.Stderr, "failed to close file %s: %v\n", fpath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -159,30 +172,54 @@ func main() {
|
|||
|
||||
_, err = file.WriteTo(w)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to send file %s: %v\n", filepath, err)
|
||||
fmt.Fprintf(os.Stderr, "failed to send file %s: %v\n", fpath, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.Redirect(w, r, r.URL.Path + "/", http.StatusFound)
|
||||
http.Redirect(w, r, r.URL.Path+"/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
data := Directory{
|
||||
Root: isRoot,
|
||||
Name: r.URL.Path,
|
||||
Files: []*File{},
|
||||
// embeded readme
|
||||
var readmeHTML template.HTML
|
||||
entries, err := os.ReadDir(fpath)
|
||||
if err == nil {
|
||||
for _, entry := range entries {
|
||||
if strings.EqualFold(entry.Name(), "readme.md") {
|
||||
src, err := os.ReadFile(filepath.Join(fpath, entry.Name()))
|
||||
if err == nil {
|
||||
mdFlags := html.CommonFlags | html.HrefTargetBlank
|
||||
mdRenderer := html.NewRenderer(html.RendererOptions{Flags: mdFlags})
|
||||
mdParser := parser.NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs)
|
||||
md := mdParser.Parse(src)
|
||||
readmeHTML = template.HTML(markdown.Render(md, mdRenderer))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fsDir := os.DirFS(filepath)
|
||||
data := Directory{
|
||||
Root: isRoot,
|
||||
Name: r.URL.Path,
|
||||
Files: []*File{},
|
||||
Readme: readmeHTML,
|
||||
}
|
||||
|
||||
fsDir := os.DirFS(fpath)
|
||||
directories, err := fs.ReadDir(fsDir, ".")
|
||||
for _, dir := range directories {
|
||||
name := dir.Name()
|
||||
if slices.Contains(ignoredFiles, name) { continue }
|
||||
if slices.Contains(ignoredFiles, name) {
|
||||
continue
|
||||
}
|
||||
|
||||
info, err := dir.Info()
|
||||
if err != nil { continue }
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var uri string
|
||||
if isRoot {
|
||||
|
|
@ -213,10 +250,10 @@ func main() {
|
|||
dateStr := info.ModTime().Format("02-Jan-2006 15:04")
|
||||
|
||||
data.Files = append(data.Files, &File{
|
||||
Name: name,
|
||||
URI: uri,
|
||||
IsDir: info.IsDir(),
|
||||
Size: sizeStr,
|
||||
Name: name,
|
||||
URI: uri,
|
||||
IsDir: info.IsDir(),
|
||||
Size: sizeStr,
|
||||
ModifiedDate: dateStr,
|
||||
})
|
||||
}
|
||||
|
|
@ -232,52 +269,60 @@ func main() {
|
|||
}
|
||||
|
||||
type LoggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
Status int
|
||||
http.ResponseWriter
|
||||
Status int
|
||||
}
|
||||
|
||||
var COL_Reset = "\033[0m"
|
||||
var COL_Red = "\033[31m"
|
||||
var COL_Green = "\033[32m"
|
||||
var COL_Reset = "\033[0m"
|
||||
var COL_Red = "\033[31m"
|
||||
var COL_Green = "\033[32m"
|
||||
var COL_Yellow = "\033[33m"
|
||||
var COL_Blue = "\033[34m"
|
||||
var COL_Blue = "\033[34m"
|
||||
var COL_Purple = "\033[35m"
|
||||
var COL_Cyan = "\033[36m"
|
||||
var COL_Gray = "\033[37m"
|
||||
var COL_White = "\033[97m"
|
||||
var COL_Cyan = "\033[36m"
|
||||
var COL_Gray = "\033[37m"
|
||||
var COL_White = "\033[97m"
|
||||
|
||||
func HTTPLog(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
|
||||
lrw := LoggingResponseWriter{w, http.StatusOK}
|
||||
lrw := LoggingResponseWriter{w, http.StatusOK}
|
||||
|
||||
next.ServeHTTP(&lrw, r)
|
||||
next.ServeHTTP(&lrw, r)
|
||||
|
||||
after := time.Now()
|
||||
difference := (after.Nanosecond() - start.Nanosecond()) / 1_000_000
|
||||
elapsed := "<1"
|
||||
if difference >= 1 {
|
||||
elapsed = strconv.Itoa(difference)
|
||||
}
|
||||
after := time.Now()
|
||||
difference := (after.Nanosecond() - start.Nanosecond()) / 1_000_000
|
||||
elapsed := "<1"
|
||||
if difference >= 1 {
|
||||
elapsed = strconv.Itoa(difference)
|
||||
}
|
||||
|
||||
statusColour := COL_Reset
|
||||
statusColour := COL_Reset
|
||||
|
||||
if lrw.Status - 600 <= 0 { statusColour = COL_Red }
|
||||
if lrw.Status - 500 <= 0 { statusColour = COL_Yellow }
|
||||
if lrw.Status - 400 <= 0 { statusColour = COL_White }
|
||||
if lrw.Status - 300 <= 0 { statusColour = COL_Green }
|
||||
if lrw.Status-600 <= 0 {
|
||||
statusColour = COL_Red
|
||||
}
|
||||
if lrw.Status-500 <= 0 {
|
||||
statusColour = COL_Yellow
|
||||
}
|
||||
if lrw.Status-400 <= 0 {
|
||||
statusColour = COL_White
|
||||
}
|
||||
if lrw.Status-300 <= 0 {
|
||||
statusColour = COL_Green
|
||||
}
|
||||
|
||||
fmt.Printf("[%s] %s %s - %s%d%s (%sms) (%s)\n",
|
||||
after.Format(time.UnixDate),
|
||||
r.Method,
|
||||
r.URL.Path,
|
||||
statusColour,
|
||||
lrw.Status,
|
||||
COL_Reset,
|
||||
elapsed,
|
||||
r.Header["User-Agent"][0])
|
||||
})
|
||||
fmt.Printf("[%s] %s %s - %s%d%s (%sms) (%s)\n",
|
||||
after.Format(time.UnixDate),
|
||||
r.Method,
|
||||
r.URL.Path,
|
||||
statusColour,
|
||||
lrw.Status,
|
||||
COL_Reset,
|
||||
elapsed,
|
||||
r.Header["User-Agent"][0])
|
||||
})
|
||||
}
|
||||
|
||||
func printHelp() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue