Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
3.5 KiB
158 lines
3.5 KiB
package assetfs |
|
|
|
import ( |
|
"bytes" |
|
"errors" |
|
"io" |
|
"io/ioutil" |
|
"net/http" |
|
"os" |
|
"path" |
|
"path/filepath" |
|
"time" |
|
) |
|
|
|
var ( |
|
defaultFileTimestamp = time.Now() |
|
) |
|
|
|
// FakeFile implements os.FileInfo interface for a given path and size |
|
type FakeFile struct { |
|
// Path is the path of this file |
|
Path string |
|
// Dir marks of the path is a directory |
|
Dir bool |
|
// Len is the length of the fake file, zero if it is a directory |
|
Len int64 |
|
// Timestamp is the ModTime of this file |
|
Timestamp time.Time |
|
} |
|
|
|
func (f *FakeFile) Name() string { |
|
_, name := filepath.Split(f.Path) |
|
return name |
|
} |
|
|
|
func (f *FakeFile) Mode() os.FileMode { |
|
mode := os.FileMode(0644) |
|
if f.Dir { |
|
return mode | os.ModeDir |
|
} |
|
return mode |
|
} |
|
|
|
func (f *FakeFile) ModTime() time.Time { |
|
return f.Timestamp |
|
} |
|
|
|
func (f *FakeFile) Size() int64 { |
|
return f.Len |
|
} |
|
|
|
func (f *FakeFile) IsDir() bool { |
|
return f.Mode().IsDir() |
|
} |
|
|
|
func (f *FakeFile) Sys() interface{} { |
|
return nil |
|
} |
|
|
|
// AssetFile implements http.File interface for a no-directory file with content |
|
type AssetFile struct { |
|
*bytes.Reader |
|
io.Closer |
|
FakeFile |
|
} |
|
|
|
func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile { |
|
if timestamp.IsZero() { |
|
timestamp = defaultFileTimestamp |
|
} |
|
return &AssetFile{ |
|
bytes.NewReader(content), |
|
ioutil.NopCloser(nil), |
|
FakeFile{name, false, int64(len(content)), timestamp}} |
|
} |
|
|
|
func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) { |
|
return nil, errors.New("not a directory") |
|
} |
|
|
|
func (f *AssetFile) Size() int64 { |
|
return f.FakeFile.Size() |
|
} |
|
|
|
func (f *AssetFile) Stat() (os.FileInfo, error) { |
|
return f, nil |
|
} |
|
|
|
// AssetDirectory implements http.File interface for a directory |
|
type AssetDirectory struct { |
|
AssetFile |
|
ChildrenRead int |
|
Children []os.FileInfo |
|
} |
|
|
|
func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory { |
|
fileinfos := make([]os.FileInfo, 0, len(children)) |
|
for _, child := range children { |
|
_, err := fs.AssetDir(filepath.Join(name, child)) |
|
fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}}) |
|
} |
|
return &AssetDirectory{ |
|
AssetFile{ |
|
bytes.NewReader(nil), |
|
ioutil.NopCloser(nil), |
|
FakeFile{name, true, 0, time.Time{}}, |
|
}, |
|
0, |
|
fileinfos} |
|
} |
|
|
|
func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) { |
|
if count <= 0 { |
|
return f.Children, nil |
|
} |
|
if f.ChildrenRead+count > len(f.Children) { |
|
count = len(f.Children) - f.ChildrenRead |
|
} |
|
rv := f.Children[f.ChildrenRead : f.ChildrenRead+count] |
|
f.ChildrenRead += count |
|
return rv, nil |
|
} |
|
|
|
func (f *AssetDirectory) Stat() (os.FileInfo, error) { |
|
return f, nil |
|
} |
|
|
|
// AssetFS implements http.FileSystem, allowing |
|
// embedded files to be served from net/http package. |
|
type AssetFS struct { |
|
// Asset should return content of file in path if exists |
|
Asset func(path string) ([]byte, error) |
|
// AssetDir should return list of files in the path |
|
AssetDir func(path string) ([]string, error) |
|
// AssetInfo should return the info of file in path if exists |
|
AssetInfo func(path string) (os.FileInfo, error) |
|
// Prefix would be prepended to http requests |
|
Prefix string |
|
} |
|
|
|
func (fs *AssetFS) Open(name string) (http.File, error) { |
|
name = path.Join(fs.Prefix, name) |
|
if len(name) > 0 && name[0] == '/' { |
|
name = name[1:] |
|
} |
|
if b, err := fs.Asset(name); err == nil { |
|
timestamp := defaultFileTimestamp |
|
if info, err := fs.AssetInfo(name); err == nil { |
|
timestamp = info.ModTime() |
|
} |
|
return NewAssetFile(name, b, timestamp), nil |
|
} |
|
if children, err := fs.AssetDir(name); err == nil { |
|
return NewAssetDirectory(name, children, fs), nil |
|
} else { |
|
return nil, err |
|
} |
|
}
|
|
|