Feat: Get file for oss handler

pull/247/head
HFO4 5 years ago
parent 286f76cbec
commit 7eda63f089

@ -11,7 +11,9 @@ import (
model "github.com/HFO4/cloudreve/models" model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx" "github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
"github.com/HFO4/cloudreve/pkg/filesystem/response" "github.com/HFO4/cloudreve/pkg/filesystem/response"
"github.com/HFO4/cloudreve/pkg/request"
"github.com/HFO4/cloudreve/pkg/serializer" "github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/util"
"github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/aliyun/aliyun-oss-go-sdk/oss"
"io" "io"
"net/url" "net/url"
@ -39,32 +41,77 @@ type Handler struct {
bucket *oss.Bucket bucket *oss.Bucket
} }
type key int
const (
// VersionID 文件版本标识
VersionID key = iota
)
// InitOSSClient 初始化OSS鉴权客户端 // InitOSSClient 初始化OSS鉴权客户端
func (handler *Handler) InitOSSClient() error { func (handler *Handler) InitOSSClient() error {
if handler.Policy == nil { if handler.Policy == nil {
return errors.New("存储策略为空") return errors.New("存储策略为空")
} }
// 初始化客户端 if handler.client == nil {
client, err := oss.New(handler.Policy.Server, handler.Policy.AccessKey, handler.Policy.SecretKey) // 初始化客户端
if err != nil { client, err := oss.New(handler.Policy.Server, handler.Policy.AccessKey, handler.Policy.SecretKey)
return err if err != nil {
} return err
handler.client = client }
handler.client = client
// 初始化存储桶
bucket, err := client.Bucket(handler.Policy.BucketName)
if err != nil {
return err
}
handler.bucket = bucket
// 初始化存储桶
bucket, err := client.Bucket(handler.Policy.BucketName)
if err != nil {
return err
} }
handler.bucket = bucket
return nil return nil
} }
// Get 获取文件 // Get 获取文件
func (handler Handler) Get(ctx context.Context, path string) (response.RSCloser, error) { func (handler Handler) Get(ctx context.Context, path string) (response.RSCloser, error) {
return nil, errors.New("未实现") // 通过VersionID禁止缓存
ctx = context.WithValue(ctx, VersionID, time.Now().UnixNano())
// 获取文件源地址
downloadURL, err := handler.Source(
ctx,
path,
url.URL{},
int64(model.GetIntSetting("preview_timeout", 60)),
false,
0,
)
if err != nil {
return nil, err
}
// 获取文件数据流
client := request.HTTPClient{}
resp, err := client.Request(
"GET",
downloadURL,
nil,
request.WithContext(ctx),
).CheckHTTPResponse(200).GetRSCloser()
if err != nil {
return nil, err
}
resp.SetFirstFakeChunk()
// 尝试自主获取文件大小
if file, ok := ctx.Value(fsctx.FileModelCtx).(model.File); ok {
resp.SetContentLength(int64(file.Size))
}
return resp, nil
} }
// Put 将文件流保存到指定目录 // Put 将文件流保存到指定目录
@ -73,14 +120,60 @@ func (handler Handler) Put(ctx context.Context, file io.ReadCloser, dst string,
} }
// Delete 删除一个或多个文件, // Delete 删除一个或多个文件,
// 返回未删除的文件,及遇到的最后一个错误 // 返回未删除的文件
func (handler Handler) Delete(ctx context.Context, files []string) ([]string, error) { func (handler Handler) Delete(ctx context.Context, files []string) ([]string, error) {
return []string{}, errors.New("未实现") // 初始化客户端
if err := handler.InitOSSClient(); err != nil {
return files, err
}
// 删除文件
delRes, err := handler.bucket.DeleteObjects(files)
if err != nil {
return files, err
}
// 统计未删除的文件
failed := util.SliceDifference(files, delRes.DeletedObjects)
if len(failed) > 0 {
return failed, errors.New("删除失败")
}
return []string{}, nil
} }
// Thumb 获取文件缩略图 // Thumb 获取文件缩略图
func (handler Handler) Thumb(ctx context.Context, path string) (*response.ContentResponse, error) { func (handler Handler) Thumb(ctx context.Context, path string) (*response.ContentResponse, error) {
return nil, errors.New("未实现") // 初始化客户端
if err := handler.InitOSSClient(); err != nil {
return nil, err
}
var (
thumbSize = [2]uint{400, 300}
ok = false
)
if thumbSize, ok = ctx.Value(fsctx.ThumbSizeCtx).([2]uint); !ok {
return nil, errors.New("无法获取缩略图尺寸设置")
}
thumbParam := fmt.Sprintf("image/resize,m_lfit,h_%d,w_%d", thumbSize[1], thumbSize[0])
thumbOption := []oss.Option{oss.Process(thumbParam)}
thumbURL, err := handler.signSourceURL(
ctx,
path,
int64(model.GetIntSetting("preview_timeout", 60)),
thumbOption,
)
if err != nil {
return nil, err
}
return &response.ContentResponse{
Redirect: true,
URL: thumbURL,
}, nil
} }
// Source 获取外链URL // Source 获取外链URL
@ -123,6 +216,10 @@ func (handler Handler) Source(
} }
func (handler Handler) signSourceURL(ctx context.Context, path string, ttl int64, options []oss.Option) (string, error) { func (handler Handler) signSourceURL(ctx context.Context, path string, ttl int64, options []oss.Option) (string, error) {
// 是否带有 Version ID
if versionID, ok := ctx.Value(VersionID).(int64); ok {
}
signedURL, err := handler.bucket.SignURL(path, oss.HTTPGet, ttl, options...) signedURL, err := handler.bucket.SignURL(path, oss.HTTPGet, ttl, options...)
if err != nil { if err != nil {
return "", err return "", err

@ -71,3 +71,38 @@ func BuildConcat(str1, str2 string, DBType string) string {
return str1 + "||" + str2 return str1 + "||" + str2
} }
} }
// SliceIntersect 求两个切片交集
func SliceIntersect(slice1, slice2 []string) []string {
m := make(map[string]int)
nn := make([]string, 0)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 1 {
nn = append(nn, v)
}
}
return nn
}
// SliceDifference 求两个切片差集
func SliceDifference(slice1, slice2 []string) []string {
m := make(map[string]int)
nn := make([]string, 0)
inter := SliceIntersect(slice1, slice2)
for _, v := range inter {
m[v]++
}
for _, value := range slice1 {
times, _ := m[value]
if times == 0 {
nn = append(nn, value)
}
}
return nn
}

@ -68,3 +68,31 @@ func TestBuildConcat(t *testing.T) {
asserts.Equal("CONCAT(1,2)", BuildConcat("1", "2", "mysql")) asserts.Equal("CONCAT(1,2)", BuildConcat("1", "2", "mysql"))
asserts.Equal("1||2", BuildConcat("1", "2", "sqlite3")) asserts.Equal("1||2", BuildConcat("1", "2", "sqlite3"))
} }
func TestSliceDifference(t *testing.T) {
asserts := assert.New(t)
{
s1 := []string{"1", "2", "3", "4"}
s2 := []string{"2", "4"}
asserts.Equal([]string{"1", "3"}, SliceDifference(s1, s2))
}
{
s2 := []string{"1", "2", "3", "4"}
s1 := []string{"2", "4"}
asserts.Equal([]string{}, SliceDifference(s1, s2))
}
{
s1 := []string{"1", "2", "3", "4"}
s2 := []string{"1", "2", "3", "4"}
asserts.Equal([]string{}, SliceDifference(s1, s2))
}
{
s1 := []string{"1", "2", "3", "4"}
s2 := []string{}
asserts.Equal([]string{"1", "2", "3", "4"}, SliceDifference(s1, s2))
}
}

@ -36,6 +36,9 @@ func QiniuCallback(c *gin.Context) {
func OSSCallback(c *gin.Context) { func OSSCallback(c *gin.Context) {
var callbackBody callback.UploadCallbackService var callbackBody callback.UploadCallbackService
if err := c.ShouldBindJSON(&callbackBody); err == nil { if err := c.ShouldBindJSON(&callbackBody); err == nil {
if callbackBody.PicInfo == "," {
callbackBody.PicInfo = ""
}
res := callback.ProcessCallback(callbackBody, c) res := callback.ProcessCallback(callbackBody, c)
c.JSON(200, res) c.JSON(200, res)
} else { } else {

Loading…
Cancel
Save