package route import ( "errors" "leech/config" "leech/html" "leech/thumbnail" "net/url" "os" "path" "sort" "strings" "github.com/gofiber/fiber/v2" ) func RecursivelyGetSize(completePath string) (int64, error) { files, err := os.ReadDir(completePath) if err != nil { return -1, err } var sum int64 for _, f := range files { dirEntryInfo, err := f.Info() if err != nil { return -1, err } dirEntrySize := dirEntryInfo.Size() if f.IsDir() { dirEntrySize, err = RecursivelyGetSize(path.Join(completePath, f.Name())) if err != nil { return -1, err } } sum += dirEntrySize } return sum, nil } func HandleList(c *fiber.Ctx) error { encodedReq := c.Path()[1:] req, err := url.QueryUnescape(encodedReq) if err != nil { return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) } c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) if req == "" { keys := make([]string, 0, len(config.Config.ServeDirs)) for k := range config.Config.ServeDirs { keys = append(keys, k) } sort.Strings(keys) entries := make([]html.Entry, 0, len(config.Config.ServeDirs)) for _, key := range keys { dirEntrySize, err := RecursivelyGetSize(config.Config.ServeDirs[key]) if err != nil { return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) } entries = append(entries, html.Entry{ Name: key, Size: dirEntrySize, IsDir: true, }) } return c.SendString(html.FileListPage(req, entries)) } else { pathSlice := strings.Split(req, "/") pathBase, ok := config.Config.ServeDirs[pathSlice[0]] if ok { pathSlice[0] = pathBase completePath := path.Join(pathSlice...) files, err := os.ReadDir(completePath) if err != nil { return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) } entries := []html.Entry{} for _, f := range files { dirEntryInfo, err := f.Info() if err != nil { return c.Status(fiber.StatusInternalServerError).SendString("Internal server error!") } dirEntrySize := dirEntryInfo.Size() if f.IsDir() { dirEntrySize, err = RecursivelyGetSize(path.Join(completePath, f.Name())) if err != nil { return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) } } entries = append(entries, html.Entry{ Name: f.Name(), Size: dirEntrySize, IsDir: f.IsDir(), }) } return c.SendString(html.FileListPage(req, entries)) } else { return c.Status(fiber.StatusNotFound).SendString("Sorry can't find that!") } } } func HandleThumb(c *fiber.Ctx) error { encodedReq := c.Path()[1:] req, err := url.QueryUnescape(encodedReq) if err != nil { return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) } c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) pathSlice := strings.Split(req, "/") pathSlice = pathSlice[1:len(pathSlice)] pathBase, ok := config.Config.ServeDirs[pathSlice[0]] if ok { pathSlice[0] = pathBase completePath := path.Join(pathSlice...) if file_info, err := os.Stat(completePath); err == nil { if file_info.IsDir() { return c.Status(fiber.StatusUnauthorized).SendString("Sorry that's a directory!") } thumbnail.GetThumbnail(c, completePath) } else if errors.Is(err, os.ErrNotExist) { return c.Status(fiber.StatusNotFound).SendString("Sorry can't find that!") } else { // Schrodinger: file may or may not exist. See err for details. // Therefore, do *NOT* use !os.IsNotExist(err) to test for file existence } } else { return c.Status(fiber.StatusNotFound).SendString("Sorry can't find that!") } return nil }