diff --git a/internal/repo/file.go b/internal/repo/file.go new file mode 100644 index 0000000..e0281bf --- /dev/null +++ b/internal/repo/file.go @@ -0,0 +1 @@ +package repo diff --git a/pkg/filedriver/base_driver.go b/pkg/filedriver/base_driver.go new file mode 100644 index 0000000..8cb2869 --- /dev/null +++ b/pkg/filedriver/base_driver.go @@ -0,0 +1,38 @@ +package filedriver + +import ( + "fmt" + "github.com/LiteyukiStudio/spage/pkg/constants" + "github.com/cloudwego/hertz/pkg/app" + "io" + "os" +) + +type FileDriver interface { + Save(ctx *app.RequestContext, path string, r io.Reader) error + Open(ctx *app.RequestContext, path string) (io.ReadCloser, error) + Delete(ctx *app.RequestContext, path string) error + Stat(ctx *app.RequestContext, path string) (os.FileInfo, error) + Get(ctx *app.RequestContext, path string) + ListDir(ctx *app.RequestContext, path string) ([]os.FileInfo, error) +} + +type DriverConfig struct { + Type string `mapstructure:"file.driver.type"` + BasePath string `mapstructure:"file.driver.base_path"` + WebDavUrl string `mapstructure:"file.driver.webdav.url"` + WebDavUser string `mapstructure:"file.driver.webdav.user"` + WebDavPassword string `mapstructure:"file.driver.webdav.password"` + WebDavPolicy string `mapstructure:"file.driver.webdav.policy"` // proxy|redirect +} + +func GetFileDriver(driverConfig *DriverConfig) (FileDriver, error) { + switch driverConfig.Type { + case constants.FileDriverLocal: + return NewLocalDriver(driverConfig), nil + case constants.FileDriverWebdav: + return NewWebDAVClientDriver(driverConfig), nil + default: + return nil, fmt.Errorf("unsupported file driver type: %s", driverConfig.Type) + } +} diff --git a/pkg/filedriver/local_driver.go b/pkg/filedriver/local_driver.go new file mode 100644 index 0000000..c5486e0 --- /dev/null +++ b/pkg/filedriver/local_driver.go @@ -0,0 +1,74 @@ +package filedriver + +import ( + "github.com/cloudwego/hertz/pkg/app" + "io" + "os" + "path/filepath" +) + +type LocalDriver struct { + BasePath string +} + +func NewLocalDriver(driverConfig *DriverConfig) *LocalDriver { + return &LocalDriver{ + BasePath: driverConfig.BasePath, + } +} + +func (d *LocalDriver) fullPath(path string) string { + return filepath.Join(d.BasePath, path) +} + +func (d *LocalDriver) Save(ctx *app.RequestContext, path string, r io.Reader) error { + full := d.fullPath(path) + if err := os.MkdirAll(filepath.Dir(full), 0755); err != nil { + return err + } + f, err := os.Create(full) + if err != nil { + return err + } + defer func(f *os.File) { + err := f.Close() + if err != nil { + + } + }(f) + _, err = io.Copy(f, r) + return err +} + +func (d *LocalDriver) Open(ctx *app.RequestContext, path string) (io.ReadCloser, error) { + return os.Open(d.fullPath(path)) +} + +func (d *LocalDriver) Get(ctx *app.RequestContext, path string) { + ctx.File(d.fullPath(path)) + ctx.Abort() +} + +func (d *LocalDriver) Delete(ctx *app.RequestContext, path string) error { + return os.Remove(d.fullPath(path)) +} + +func (d *LocalDriver) Stat(ctx *app.RequestContext, path string) (os.FileInfo, error) { + return os.Stat(d.fullPath(path)) +} + +func (d *LocalDriver) ListDir(ctx *app.RequestContext, path string) ([]os.FileInfo, error) { + entries, err := os.ReadDir(d.fullPath(path)) + if err != nil { + return nil, err + } + infos := make([]os.FileInfo, 0, len(entries)) + for _, entry := range entries { + info, err := entry.Info() + if err != nil { + return nil, err + } + infos = append(infos, info) + } + return infos, nil +} diff --git a/pkg/filedriver/webdav_driver.go b/pkg/filedriver/webdav_driver.go new file mode 100644 index 0000000..2ea90f5 --- /dev/null +++ b/pkg/filedriver/webdav_driver.go @@ -0,0 +1,76 @@ +package filedriver + +import ( + "bytes" + "fmt" + "github.com/LiteyukiStudio/spage/pkg/constants" + "github.com/LiteyukiStudio/spage/pkg/resps" + "github.com/cloudwego/hertz/pkg/app" + "io" + "os" + "path" + + "github.com/studio-b12/gowebdav" +) + +type WebDAVClientDriver struct { + client *gowebdav.Client + config *DriverConfig + BasePath string +} + +func NewWebDAVClientDriver(driverConfig *DriverConfig) *WebDAVClientDriver { + c := gowebdav.NewClient(driverConfig.WebDavUrl, driverConfig.WebDavUser, driverConfig.WebDavPassword) + return &WebDAVClientDriver{client: c, BasePath: driverConfig.BasePath, config: driverConfig} +} + +func (d *WebDAVClientDriver) fullPath(p string) string { + if d.BasePath == "" { + return p + } + return path.Join(d.BasePath, p) +} + +func (d *WebDAVClientDriver) Save(ctx *app.RequestContext, p string, r io.Reader) error { + data, err := io.ReadAll(r) + if err != nil { + return err + } + return d.client.Write(d.fullPath(p), data, 0644) +} + +func (d *WebDAVClientDriver) Open(ctx *app.RequestContext, p string) (io.ReadCloser, error) { + data, err := d.client.Read(d.fullPath(p)) + if err != nil { + return nil, err + } + return io.NopCloser(bytes.NewReader(data)), nil +} + +func (d *WebDAVClientDriver) Get(ctx *app.RequestContext, p string) { + if d.config.WebDavPolicy == constants.WebDavPolicyRedirect { + ctx.Redirect(302, []byte(d.config.WebDavUrl+d.fullPath(p))) + return + } else { + data, err := d.client.Read(d.fullPath(p)) + if err != nil { + resps.InternalServerError(ctx, err.Error()) + return + } + ctx.SetBodyStream(bytes.NewReader(data), len(data)) + ctx.Response.Header.Set("Content-Type", "application/octet-stream") + ctx.Response.Header.Set("Content-Length", fmt.Sprintf("%d", len(data))) + } +} + +func (d *WebDAVClientDriver) Delete(ctx *app.RequestContext, p string) error { + return d.client.Remove(d.fullPath(p)) +} + +func (d *WebDAVClientDriver) Stat(ctx *app.RequestContext, p string) (os.FileInfo, error) { + return d.client.Stat(d.fullPath(p)) +} + +func (d *WebDAVClientDriver) ListDir(ctx *app.RequestContext, p string) ([]os.FileInfo, error) { + return d.client.ReadDir(d.fullPath(p)) +} diff --git a/pkg/utils/file.go b/pkg/utils/file.go new file mode 100644 index 0000000..d4b585b --- /dev/null +++ b/pkg/utils/file.go @@ -0,0 +1 @@ +package utils