Feat: download file and get file downloading session

This commit is contained in:
HFO4
2019-12-13 20:46:11 +08:00
parent ad02a659a6
commit f262caf1f5
10 changed files with 150 additions and 18 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/HFO4/cloudreve/pkg/util"
"github.com/juju/ratelimit"
"io"
"strconv"
)
/* ============
@@ -105,8 +106,8 @@ func (fs *FileSystem) GetContent(ctx context.Context, path string) (io.ReadSeeke
return nil, ErrObjectNotExist
}
fs.FileTarget = []model.File{*file}
ctx = context.WithValue(ctx, fsctx.FileModelCtx, file)
}
ctx = context.WithValue(ctx, fsctx.FileModelCtx, fs.FileTarget[0])
// 将当前存储策略重设为文件使用的
fs.Policy = fs.FileTarget[0].GetPolicy()
@@ -173,6 +174,45 @@ func (fs *FileSystem) GroupFileByPolicy(ctx context.Context, files []model.File)
return policyGroup
}
// GetDownloadURL 创建文件下载链接
func (fs *FileSystem) GetDownloadURL(ctx context.Context, path string) (string, error) {
// 找到文件
if len(fs.FileTarget) == 0 {
exist, file := fs.IsFileExist(path)
if !exist {
return "", ErrObjectNotExist
}
fs.FileTarget = []model.File{*file}
}
ctx = context.WithValue(ctx, fsctx.FileModelCtx, fs.FileTarget[0])
// 将当前存储策略重设为文件使用的
fs.Policy = fs.FileTarget[0].GetPolicy()
err := fs.dispatchHandler()
if err != nil {
return "", err
}
// 生成下載地址
siteURL := model.GetSiteURL()
ttl, err := strconv.ParseInt(model.GetSettingByName("download_timeout"), 10, 64)
if err != nil {
return "", serializer.NewError(serializer.CodeInternalSetting, "无法获取下载地址有效期", err)
}
source, err := fs.Handler.GetDownloadURL(
ctx,
fs.FileTarget[0].SourceName,
*siteURL,
ttl,
)
if err != nil {
return "", serializer.NewError(serializer.CodeNotSet, "无法获取下载地址", err)
}
return source, nil
}
// GetSource 获取可直接访问文件的外链地址
func (fs *FileSystem) GetSource(ctx context.Context, fileID uint) (string, error) {
// 查找文件记录

View File

@@ -32,6 +32,8 @@ type Handler interface {
Thumb(ctx context.Context, path string) (*response.ContentResponse, error)
// 获取外链地址url
Source(ctx context.Context, path string, url url.URL, expires int64) (string, error)
//获取下载地址
GetDownloadURL(ctx context.Context, path string, url url.URL, expires int64) (string, error)
}
// FileSystem 管理文件的文件系统

View File

@@ -6,6 +6,7 @@ import (
"fmt"
model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/auth"
"github.com/HFO4/cloudreve/pkg/cache"
"github.com/HFO4/cloudreve/pkg/conf"
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
"github.com/HFO4/cloudreve/pkg/filesystem/response"
@@ -15,6 +16,7 @@ import (
"net/url"
"os"
"path/filepath"
"time"
)
// Handler 本地策略适配器
@@ -127,3 +129,29 @@ func (handler Handler) Source(ctx context.Context, path string, url url.URL, exp
finalURL := url.ResolveReference(signedURI).String()
return finalURL, nil
}
func (handler Handler) GetDownloadURL(ctx context.Context, path string, url url.URL, ttl int64) (string, error) {
file, ok := ctx.Value(fsctx.FileModelCtx).(model.File)
if !ok {
return "", errors.New("无法获取文件记录上下文")
}
// 创建下载会话,将文件信息写入缓存
downloadSessionID := util.RandStringRunes(16)
err := cache.Set("download_"+downloadSessionID, file, int(ttl))
if err != nil {
return "", serializer.NewError(serializer.CodeCacheOperation, "无法创建下載会话", err)
}
// 签名生成文件记录
signedURI, err := auth.SignURI(
fmt.Sprintf("/api/v3/file/download/%s", downloadSessionID),
time.Now().Unix()+ttl,
)
if err != nil {
return "", serializer.NewError(serializer.CodeEncryptError, "无法对URL进行签名", err)
}
finalURL := url.ResolveReference(signedURI).String()
return finalURL, nil
}

View File

@@ -46,6 +46,10 @@ func (m FileHeaderMock) Source(ctx context.Context, path string, url url.URL, ex
args := m.Called(ctx, path, url, expires)
return args.Get(0).(string), args.Error(1)
}
func (m FileHeaderMock) GetDownloadURL(ctx context.Context, path string, url url.URL, expires int64) (string, error) {
args := m.Called(ctx, path, url, expires)
return args.Get(0).(string), args.Error(1)
}
func TestFileSystem_Upload(t *testing.T) {
asserts := assert.New(t)

View File

@@ -66,6 +66,10 @@ const (
CodeEncryptError = 50002
// CodeIOFailed IO操作失败
CodeIOFailed = 50004
// CodeInternalSetting 内部设置参数错误
CodeInternalSetting = 50005
// CodeCacheOperation 缓存操作失败
CodeCacheOperation = 50006
//CodeParamErr 各种奇奇怪怪的参数错误
CodeParamErr = 40001
// CodeNotSet 未定错误后续尝试从error中获取