|
|
|
package model
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/HFO4/cloudreve/pkg/util"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Policy 存储策略
|
|
|
|
type Policy struct {
|
|
|
|
// 表字段
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
Type string
|
|
|
|
Server string
|
|
|
|
BucketName string
|
|
|
|
IsPrivate bool
|
|
|
|
BaseURL string
|
|
|
|
AccessKey string `gorm:"size:512"`
|
|
|
|
SecretKey string `gorm:"size:512"`
|
|
|
|
MaxSize uint64
|
|
|
|
AutoRename bool
|
|
|
|
DirNameRule string
|
|
|
|
FileNameRule string
|
|
|
|
IsOriginLinkEnable bool
|
|
|
|
Options string `gorm:"size:4096"`
|
|
|
|
|
|
|
|
// 数据库忽略字段
|
|
|
|
OptionsSerialized PolicyOption `gorm:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolicyOption 非公有的存储策略属性
|
|
|
|
type PolicyOption struct {
|
|
|
|
OPName string `json:"op_name"`
|
|
|
|
OPPassword string `json:"op_pwd"`
|
|
|
|
FileType []string `json:"file_type"`
|
|
|
|
MimeType string `json:"mimetype"`
|
|
|
|
RangeTransferEnabled bool `json:"range_transfer_enabled"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// 存储策略缓存,部分情况下需要频繁查询存储策略
|
|
|
|
var policyCache = make(map[uint]Policy)
|
|
|
|
var rw sync.RWMutex
|
|
|
|
|
|
|
|
// GetPolicyByID 用ID获取存储策略
|
|
|
|
func GetPolicyByID(ID interface{}) (Policy, error) {
|
|
|
|
// 尝试读取缓存
|
|
|
|
rw.RLock()
|
|
|
|
if policy, ok := policyCache[ID.(uint)]; ok {
|
|
|
|
rw.RUnlock()
|
|
|
|
return policy, nil
|
|
|
|
}
|
|
|
|
rw.RUnlock()
|
|
|
|
|
|
|
|
var policy Policy
|
|
|
|
result := DB.First(&policy, ID)
|
|
|
|
|
|
|
|
// 写入缓存
|
|
|
|
if result.Error == nil {
|
|
|
|
rw.Lock()
|
|
|
|
policyCache[policy.ID] = policy
|
|
|
|
rw.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
return policy, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// AfterFind 找到存储策略后的钩子
|
|
|
|
func (policy *Policy) AfterFind() (err error) {
|
|
|
|
// 解析存储策略设置到OptionsSerialized
|
|
|
|
err = json.Unmarshal([]byte(policy.Options), &policy.OptionsSerialized)
|
|
|
|
if policy.OptionsSerialized.FileType == nil {
|
|
|
|
policy.OptionsSerialized.FileType = []string{}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// BeforeSave Save策略前的钩子
|
|
|
|
func (policy *Policy) BeforeSave() (err error) {
|
|
|
|
err = policy.SerializeOptions()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
//SerializeOptions 将序列后的Option写入到数据库字段
|
|
|
|
func (policy *Policy) SerializeOptions() (err error) {
|
|
|
|
optionsValue, err := json.Marshal(&policy.OptionsSerialized)
|
|
|
|
policy.Options = string(optionsValue)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GeneratePath 生成存储文件的路径
|
|
|
|
func (policy *Policy) GeneratePath(uid uint, path string) string {
|
|
|
|
dirRule := policy.DirNameRule
|
|
|
|
replaceTable := map[string]string{
|
|
|
|
"{randomkey16}": util.RandStringRunes(16),
|
|
|
|
"{randomkey8}": util.RandStringRunes(8),
|
|
|
|
"{timestamp}": strconv.FormatInt(time.Now().Unix(), 10),
|
|
|
|
"{uid}": strconv.Itoa(int(uid)),
|
|
|
|
"{datetime}": time.Now().Format("20060102150405"),
|
|
|
|
"{date}": time.Now().Format("20060102"),
|
|
|
|
"{path}": path + "/",
|
|
|
|
}
|
|
|
|
dirRule = util.Replace(replaceTable, dirRule)
|
|
|
|
return filepath.Clean(dirRule)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GenerateFileName 生成存储文件名
|
|
|
|
func (policy *Policy) GenerateFileName(uid uint, origin string) string {
|
|
|
|
// 未开启自动重命名时,直接返回原始文件名
|
|
|
|
if !policy.AutoRename {
|
|
|
|
return origin
|
|
|
|
}
|
|
|
|
|
|
|
|
fileRule := policy.FileNameRule
|
|
|
|
|
|
|
|
replaceTable := map[string]string{
|
|
|
|
"{randomkey16}": util.RandStringRunes(16),
|
|
|
|
"{randomkey8}": util.RandStringRunes(8),
|
|
|
|
"{timestamp}": strconv.FormatInt(time.Now().Unix(), 10),
|
|
|
|
"{uid}": strconv.Itoa(int(uid)),
|
|
|
|
"{datetime}": time.Now().Format("20060102150405"),
|
|
|
|
"{date}": time.Now().Format("20060102"),
|
|
|
|
}
|
|
|
|
|
|
|
|
// 部分存储策略可以使用{origin}代表原始文件名
|
|
|
|
switch policy.Type {
|
|
|
|
case "qiniu":
|
|
|
|
// 七牛会将$(fname)自动替换为原始文件名
|
|
|
|
replaceTable["{originname}"] = "$(fname)"
|
|
|
|
case "local":
|
|
|
|
replaceTable["{originname}"] = origin
|
|
|
|
case "oss":
|
|
|
|
// OSS会将${filename}自动替换为原始文件名
|
|
|
|
replaceTable["{originname}"] = "${filename}"
|
|
|
|
case "upyun":
|
|
|
|
// Upyun会将{filename}{.suffix}自动替换为原始文件名
|
|
|
|
replaceTable["{originname}"] = "{filename}{.suffix}"
|
|
|
|
}
|
|
|
|
|
|
|
|
fileRule = util.Replace(replaceTable, fileRule)
|
|
|
|
return fileRule
|
|
|
|
}
|