update
This commit is contained in:
71
internal/pkg/storage/storage.go
Normal file
71
internal/pkg/storage/storage.go
Normal file
@ -0,0 +1,71 @@
|
||||
// Package storage 抽象「把一段图片字节存成可访问地址」的实现。
|
||||
//
|
||||
// 两种实现:
|
||||
// - LocalUploader:落到本地磁盘,对外以静态路径暴露(兜底/默认实现)。
|
||||
// - QiniuUploader:直传七牛云对象存储(标准库实现,无第三方 SDK 依赖)。
|
||||
//
|
||||
// 入库 worker 主用 Qiniu(若启用),单张失败时兜底写本地,避免图片完全丢失。
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Uploader 抽象图片上传。
|
||||
// Upload 返回写入数据库的图片访问地址:
|
||||
// - Qiniu 返回完整 https URL(base_url + key)
|
||||
// - 本地实现返回 Upload.URLPrefix + "/" + key 的相对路径
|
||||
type Uploader interface {
|
||||
// Upload 上传 data 到 key 指定的对象,返回访问 URL。
|
||||
Upload(ctx context.Context, key string, data []byte, contentType string) (string, error)
|
||||
// Enabled 表示该实现是否真正启用(用于日志/兜底判断)。
|
||||
Enabled() bool
|
||||
}
|
||||
|
||||
// Deleter 抽象图片删除(清理孤儿文件用)。
|
||||
// QiniuUploader / LocalUploader 都实现本接口;仅当某 key 在所有图集/草稿表中
|
||||
// 引用计数归零时才由调用方触发,避免误删仍被引用的文件。
|
||||
type Deleter interface {
|
||||
// Delete 删除 key 指定的对象/文件。key 不存在时按成功处理(幂等)。
|
||||
Delete(ctx context.Context, key string) error
|
||||
}
|
||||
|
||||
// LocalUploader 把文件落到本地磁盘并对外以静态路径暴露(兜底/默认实现)。
|
||||
type LocalUploader struct {
|
||||
Dir string
|
||||
URLPrefix string
|
||||
}
|
||||
|
||||
// NewLocalUploader 构造本地上传器。
|
||||
func NewLocalUploader(dir, urlPrefix string) *LocalUploader {
|
||||
return &LocalUploader{Dir: dir, URLPrefix: strings.TrimRight(urlPrefix, "/")}
|
||||
}
|
||||
|
||||
// Enabled 本地上传始终可用。
|
||||
func (l *LocalUploader) Enabled() bool { return true }
|
||||
|
||||
// Upload 写本地文件并返回相对静态路径(如 /uploads/runway/xxx.jpg)。
|
||||
func (l *LocalUploader) Upload(ctx context.Context, key string, data []byte, contentType string) (string, error) {
|
||||
abs := filepath.Join(l.Dir, filepath.FromSlash(key))
|
||||
if err := os.MkdirAll(filepath.Dir(abs), 0o755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.WriteFile(abs, data, 0o644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return l.URLPrefix + "/" + strings.TrimLeft(key, "/"), nil
|
||||
}
|
||||
|
||||
// Delete 删除本地文件(清理孤儿图用)。key 可能带 URLPrefix 前缀,先剥掉再定位磁盘文件。
|
||||
func (l *LocalUploader) Delete(ctx context.Context, key string) error {
|
||||
rel := strings.TrimPrefix(key, l.URLPrefix)
|
||||
rel = strings.TrimPrefix(rel, "/")
|
||||
abs := filepath.Join(l.Dir, filepath.FromSlash(rel))
|
||||
if err := os.Remove(abs); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user