package fs import ( "context" "fmt" _ "image/gif" _ "image/jpeg" _ "image/png" "io" "io/fs" _ "golang.org/x/image/bmp" _ "golang.org/x/image/webp" "source.toby3d.me/toby3d/home/internal/domain" "source.toby3d.me/toby3d/home/internal/resource" ) type fileServerResourceRepository struct { root fs.FS } func NewFileServerResourceRepository(root fs.FS) resource.Repository { return &fileServerResourceRepository{ root: root, } } func (repo *fileServerResourceRepository) Get(ctx context.Context, p string) (*domain.Resource, error) { info, err := fs.Stat(repo.root, p) if err != nil { return nil, fmt.Errorf("cannot stat resource on path '%s': %w", p, err) } f, err := repo.root.Open(p) if err != nil { return nil, fmt.Errorf("cannot open resource on path '%s': %w", p, err) } defer f.Close() content, err := io.ReadAll(f) if err != nil { return nil, fmt.Errorf("cannot read resource content on path '%s': %w", p, err) } return domain.NewResource(info.ModTime(), content, p), nil } func (repo *fileServerResourceRepository) Fetch(ctx context.Context, pattern string) (domain.Resources, int, error) { var ( err error matches []string ) if pattern != "" { if matches, err = fs.Glob(repo.root, pattern); err != nil { return nil, 0, fmt.Errorf("cannot match any resource by pattern '%s': %w", pattern, err) } } else { if err = fs.WalkDir(repo.root, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return fmt.Errorf("catched error while walk: %w", err) } if d.IsDir() { return nil } matches = append(matches, path) return nil }); err != nil { return nil, 0, fmt.Errorf("cannot walk through resource directories: %w", err) } } out := make(domain.Resources, 0, len(matches)) for i := range matches { if r, err := repo.Get(ctx, matches[i]); err == nil { out = append(out, r) } } return out, len(out), nil }