// // dir_render.go // Copyright (C) 2024 veypi // 2024-10-18 19:35 // Distributed under terms of the GPL license. // package webdav import ( "embed" "fmt" "html/template" "io/fs" "net/http" "net/url" "strings" "github.com/veypi/utils/logv" ) type anyDirs interface { len() int name(i int) string isDir(i int) bool } type fileInfoDirs []fs.FileInfo func (d fileInfoDirs) len() int { return len(d) } func (d fileInfoDirs) isDir(i int) bool { return d[i].IsDir() } func (d fileInfoDirs) name(i int) string { return d[i].Name() } type dirEntryDirs []fs.DirEntry func (d dirEntryDirs) len() int { return len(d) } func (d dirEntryDirs) isDir(i int) bool { return d[i].IsDir() } func (d dirEntryDirs) name(i int) string { return d[i].Name() } //go:embed dir.html var dirTemplate embed.FS // 嵌入文件系统 func size2Label(s int64) string { if s < 1024 { return fmt.Sprintf("%d B", s) } else if s < 1048576 { return fmt.Sprintf("%d KB", s/1024) } else if s < 1073741824 { return fmt.Sprintf("%d MB", s/1024/1024) } else { return fmt.Sprintf("%d MB", s/1024/1024/1024) } } func dirList(w http.ResponseWriter, r *http.Request, f File, rootPath string) { // Prefer to use ReadDir instead of Readdir, // because the former doesn't require calling // Stat on every entry of a directory on Unix. var err error defer func() { if e := recover(); e != nil { err = fmt.Errorf("%v", e) } if err != nil { logv.Warn().Msgf("http: error reading directory: %v", err) http.Error(w, "Error reading directory", http.StatusInternalServerError) } }() dir_count := 0 f_count := 0 var file_bytes int64 files := make([][4]any, 0, 5) dirs := make([][4]any, 0, 5) if d, ok := f.(fs.ReadDirFile); ok { for _, item := range logv.AssertFuncErr(d.ReadDir(-1)) { if item.IsDir() { name := item.Name() + "/" dir_count += 1 fstat, _ := item.Info() furl := url.URL{Path: name} dirs = append(dirs, [4]any{name, furl.String(), "-----", fstat.ModTime().UTC()}) } else { name := item.Name() f_count += 1 fstat, _ := item.Info() file_bytes += fstat.Size() furl := url.URL{Path: name} files = append(files, [4]any{name, furl.String(), size2Label(fstat.Size()), fstat.ModTime().UTC()}) } } } else { for _, item := range logv.AssertFuncErr(d.ReadDir(-1)) { name := item.Name() f_count += 1 fstat, _ := item.Info() file_bytes += fstat.Size() furl := url.URL{Path: name} files = append(files, [4]any{name, furl.String(), size2Label(fstat.Size()), fstat.ModTime().UTC()}) } } dirBody := logv.AssertFuncErr(dirTemplate.ReadFile("dir.html")) w.Header().Set("Content-Type", "text/html; charset=utf-8") tpl := logv.AssertFuncErr(template.New("").Parse(string(dirBody))) logv.AssertError(tpl.Execute(w, map[string]any{"files": files, "dirs": dirs, "path": strings.Split(rootPath, "/"), "cdir": dir_count, "cfile": f_count, "size": size2Label(file_bytes)})) }