Files

86 lines
1.8 KiB
Go
Executable File

package files
import (
"os"
"path"
"path/filepath"
"sort"
"strings"
"ddc/internal/extract"
)
const (
maxTreeEntries = 20000
maxTreeDepth = 32
)
type Node struct {
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"isDir"`
IsArchive bool `json:"isArchive"`
Size int64 `json:"size"`
Children []Node `json:"children,omitempty"`
}
func BuildTree(root string) ([]Node, error) {
entryCount := 0
return readLevel(root, "", 0, &entryCount)
}
func readLevel(root, relative string, depth int, entryCount *int) ([]Node, error) {
entries, err := os.ReadDir(filepath.Join(root, relative))
if err != nil {
return nil, err
}
nodes := make([]Node, 0, len(entries))
for _, entry := range entries {
if *entryCount >= maxTreeEntries {
break
}
entryType := entry.Type()
if IsInternal(entry.Name()) || (!entryType.IsDir() && !entryType.IsRegular()) {
continue
}
*entryCount++
node := Node{
Name: entry.Name(),
Path: path.Join(filepath.ToSlash(relative), entry.Name()),
IsDir: entry.IsDir(),
}
if node.IsDir {
if depth < maxTreeDepth {
children, err := readLevel(root, filepath.Join(relative, entry.Name()), depth+1, entryCount)
if err != nil {
return nil, err
}
node.Children = children
for _, child := range children {
node.Size += child.Size
}
}
} else {
info, err := entry.Info()
if err != nil {
continue
}
node.Size = info.Size()
node.IsArchive = extract.IsArchive(entry.Name())
}
nodes = append(nodes, node)
}
sort.SliceStable(nodes, func(first, second int) bool {
if nodes[first].IsDir != nodes[second].IsDir {
return nodes[first].IsDir
}
return strings.ToLower(nodes[first].Name) < strings.ToLower(nodes[second].Name)
})
return nodes, nil
}