164 lines
4.2 KiB
Go
164 lines
4.2 KiB
Go
package localfs
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"litepan/internal/domain"
|
|
"litepan/internal/driver"
|
|
)
|
|
|
|
// Addition 是本地文件系统驱动的配置。
|
|
type Addition struct {
|
|
RootPath string `json:"root_path" form:"required,full" type:"local_dir" label:"本地根目录"`
|
|
}
|
|
|
|
// Driver 把本地目录作为网盘驱动(路径型 ID)。
|
|
type Driver struct {
|
|
add Addition
|
|
rootReal string
|
|
}
|
|
|
|
var config = driver.Config{
|
|
Name: "localfs",
|
|
DisplayName: "本机存储",
|
|
Description: "适合将 STRM 目录通过 WebDAV 暴露给爆米花等播放器",
|
|
CardTags: []string{"本地目录", "容器挂载"},
|
|
SortOrder: 100,
|
|
AuthLabel: "本地",
|
|
CardColor: "#64748b",
|
|
CardLogo: "/logos/local.png",
|
|
DefaultRoot: "/",
|
|
AuthType: driver.AuthNone,
|
|
}
|
|
|
|
func New() driver.Driver { return &Driver{} }
|
|
|
|
func (d *Driver) Config() driver.Config { return config }
|
|
|
|
func (d *Driver) GetAddition() any { return &d.add }
|
|
|
|
func (d *Driver) Init(ctx context.Context) error {
|
|
_ = ctx
|
|
raw := strings.TrimSpace(d.add.RootPath)
|
|
if raw == "" {
|
|
raw = "/"
|
|
}
|
|
abs, err := filepath.Abs(raw)
|
|
if err != nil {
|
|
return domain.Wrap(domain.CodeValidation, err)
|
|
}
|
|
info, err := os.Stat(abs)
|
|
if err != nil {
|
|
return domain.Wrap(domain.CodeValidation, err)
|
|
}
|
|
if !info.IsDir() {
|
|
return domain.Errorf(domain.CodeValidation, "本地路径不是目录")
|
|
}
|
|
real, err := filepath.EvalSymlinks(abs)
|
|
if err != nil {
|
|
return domain.Wrap(domain.CodeValidation, err)
|
|
}
|
|
d.add.RootPath = abs
|
|
d.rootReal = filepath.Clean(real)
|
|
return nil
|
|
}
|
|
|
|
func (d *Driver) Drop(ctx context.Context) error { return nil }
|
|
|
|
func (d *Driver) Ping(ctx context.Context) error {
|
|
_, err := os.Stat(d.root())
|
|
if err != nil {
|
|
return domain.Wrap(domain.CodeDriverError, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *Driver) ExplainConnectionError(technical string, saving bool) string {
|
|
prefix := "添加失败"
|
|
if saving {
|
|
prefix = "保存失败"
|
|
}
|
|
lower := strings.ToLower(technical)
|
|
switch {
|
|
case strings.Contains(lower, "no such file") || strings.Contains(technical, "路径不存在"):
|
|
return prefix + ":本地路径不存在,请确认目录已挂载且路径正确"
|
|
case strings.Contains(lower, "not a directory") || strings.Contains(technical, "不是目录"):
|
|
return prefix + ":请填写目录路径,而不是文件路径"
|
|
case strings.Contains(lower, "permission") || strings.Contains(technical, "不可读"):
|
|
return prefix + ":本地路径不可读,请检查读取权限"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (d *Driver) ListFiles(ctx context.Context, parentID string) ([]domain.FileItem, error) {
|
|
_ = ctx
|
|
dir, err := d.resolveDir(parentID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return nil, domain.Wrap(domain.CodeDriverError, err)
|
|
}
|
|
items := make([]domain.FileItem, 0, len(entries))
|
|
for _, e := range entries {
|
|
info, err := e.Info()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
items = append(items, domain.FileItem{
|
|
ID: filepath.Join(dir, e.Name()),
|
|
Name: e.Name(),
|
|
Size: info.Size(),
|
|
IsDir: e.IsDir(),
|
|
ModTime: info.ModTime(),
|
|
IDKind: domain.IDPath,
|
|
})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func (d *Driver) GetFileInfo(_ context.Context, fileID string) (*domain.FileItem, error) {
|
|
target, err := d.resolveEntry(fileID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
info, err := os.Stat(target)
|
|
if err != nil {
|
|
return nil, domain.Wrap(domain.CodeNotFound, err)
|
|
}
|
|
return &domain.FileItem{
|
|
ID: target,
|
|
Name: info.Name(),
|
|
Size: info.Size(),
|
|
IsDir: info.IsDir(),
|
|
ModTime: info.ModTime(),
|
|
IDKind: domain.IDPath,
|
|
}, nil
|
|
}
|
|
|
|
func (d *Driver) root() string {
|
|
if d.add.RootPath == "" {
|
|
return "/"
|
|
}
|
|
return d.add.RootPath
|
|
}
|
|
|
|
func init() { driver.Register(New) }
|
|
|
|
var (
|
|
_ driver.ConnectionErrorExplainer = (*Driver)(nil)
|
|
_ driver.InfoGetter = (*Driver)(nil)
|
|
_ driver.Downloader = (*Driver)(nil)
|
|
_ driver.FolderCreator = (*Driver)(nil)
|
|
_ driver.Deleter = (*Driver)(nil)
|
|
_ driver.Mover = (*Driver)(nil)
|
|
_ driver.Copier = (*Driver)(nil)
|
|
_ driver.Renamer = (*Driver)(nil)
|
|
_ driver.LocalUploader = (*Driver)(nil)
|
|
)
|