git.sophuwu.com > cdn   
              117
            
             package fileserver

import (
	"fmt"
	"html/template"
	"io"
	"net/http"
	"path/filepath"
	"strings"
)

type DirEntry struct {
	Name     string
	FullName string
	Size     int
	IsDir    bool
}

func (d DirEntry) Si() string {
	if d.IsDir {
		return ""
	}
	f := float64(d.Size)
	i := 0
	for f > 1024 {
		f /= 1024
		i++
	}
	s := fmt.Sprintf("%.2f", f)
	s = strings.TrimRight(s, ".0")
	return fmt.Sprintf("%s %cB", s, " KMGTPEZY"[i])
}

type TemplateData struct {
	Path  string
	Dirs  []DirEntry
	Items []DirEntry
}

var Temp *template.Template

func FillTemp(w io.Writer, path string, items []DirEntry) error {
	var data = TemplateData{Path: path, Dirs: []DirEntry{}, Items: []DirEntry{}}
	for _, item := range items {
		if item.IsDir {
			data.Dirs = append(data.Dirs, item)
		} else {
			data.Items = append(data.Items, item)
		}
	}
	return Temp.ExecuteTemplate(w, "index", data)
}

func init() {
	Temp = template.New("index")
	Temp.Parse(`{{ define "index" }}
<!DOCTYPE html>
<html>
<head>
<title>{{ .Path }}</title>
<style>
:root {--bord: #ccc;--fg: #fff;}
body {width: calc(100% - 2ch);margin: auto auto auto auto ;max-width: 800px;background: #262833;color: var(--fg);font-family: sans-serif;}
.trees {width: 100%;display: flex;flex-direction: column;padding: 0;margin: auto auto;border: 1px solid var(--bord);border-radius: 1ch;overflow: hidden;}
.trees a {display: contents;text-decoration: none;}
.filelabel {padding: 8px;font-size: 1rem;width: auto;margin: 0;display: grid;grid-template-columns: auto auto;grid-gap: 1ch;justify-content: space-between;align-items: center;border-radius: 0;background: transparent;}
.trees > a > *  {border-bottom: 1px solid var(--bord);background: #1c1e26;}
.trees > a > *:hover {background: #2c2e46;}
.trees > a:last-child > *  {border-bottom: none;}
a {color: var(--fg);text-decoration: none;}
.filelabel > :last-child {text-align: right;}
</style>
</head>
<body>
<h1>Index of: {{.Path}}</h1>
<div class="trees">
{{ range .Dirs }}
<a href="{{ .FullName }}"><div class="filelabel"><span>{{ .Name }}</span><span>{{ .Si }}</span></div></a>
{{ end }}
{{ range .Items }}
<a href="{{ .FullName }}"><div class="filelabel"><span>{{ .Name }}</span><span>{{ .Si }}</span></div></a>
{{ end }}
</div>
</body>
</html>
{{ end }}`)
}

func Handler(prefix string, dir func(string) ([]byte, []DirEntry, error)) (string, http.Handler) {
	return prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		data, items, err := dir(strings.TrimPrefix(r.URL.Path, prefix))
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}
		w.WriteHeader(http.StatusOK)
		if data != nil {
			w.Write(data)
			return
		}
		items = append([]DirEntry{{
			Name:     "../",
			FullName: filepath.Dir(strings.TrimSuffix(r.URL.Path, "/")),
			Size:     0,
			IsDir:    true,
		}}, items...)

		err = FillTemp(w, r.URL.Path, items)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	})
}

func Handle(prefix string, dir func(string) ([]byte, []DirEntry, error)) {
	http.Handle(Handler(prefix, dir))
}