base-golang/pkg/qiniu/storage.go

230 lines
6.5 KiB
Go
Raw Normal View History

2024-07-23 10:23:43 +08:00
package qiniu
import (
"context"
"errors"
"fmt"
2024-07-31 16:49:14 +08:00
"gitea.bvbej.com/bvbej/base-golang/pkg/md5"
2024-09-29 10:25:28 +08:00
"github.com/qiniu/go-sdk/v7/auth"
"github.com/qiniu/go-sdk/v7/cdn"
"github.com/qiniu/go-sdk/v7/storagev2/credentials"
"github.com/qiniu/go-sdk/v7/storagev2/downloader"
"github.com/qiniu/go-sdk/v7/storagev2/http_client"
"github.com/qiniu/go-sdk/v7/storagev2/objects"
"github.com/qiniu/go-sdk/v7/storagev2/uploader"
"github.com/qiniu/go-sdk/v7/storagev2/uptoken"
2024-07-23 10:23:43 +08:00
"github.com/tidwall/gjson"
"io"
"net/http"
"net/url"
"path"
"strings"
"time"
)
2024-09-29 10:25:28 +08:00
type Qhash string
const (
QSha1 Qhash = "sha1"
QSha256 Qhash = "sha256"
)
2024-07-23 10:23:43 +08:00
var _ QiNiu = (*qiNiu)(nil)
type QiNiu interface {
2024-09-29 10:25:28 +08:00
SetDefaultUploadTokenTTL(duration time.Duration)
GetUploadToken() (string, error)
GetCallbackUploadToken(callbackURL string) (string, error)
TimestampSecuritySign(urlStr string, ttl time.Duration) (string, error)
UploadFile(key, localFile, callbackURL string) (*PutRet, error)
GetPrivateURL(key string, ttl time.Duration) (string, error)
2024-07-23 10:23:43 +08:00
VerifyCallback(req *http.Request) (bool, error)
2024-09-29 10:25:28 +08:00
GetFileInfo(key string) (*objects.ObjectDetails, error)
2024-07-23 10:23:43 +08:00
DelFile(key string) error
2024-09-29 10:25:28 +08:00
ListFiles(keyPrefix, marker string, limit uint64) ([]objects.ObjectDetails, error)
GetFileHash(path string, qhash Qhash) (hash string, err error)
2024-07-23 10:23:43 +08:00
}
type qiNiu struct {
bucket string
domain string
securityKey string
2024-09-29 10:25:28 +08:00
credentials *auth.Credentials
bucketManager *objects.Bucket
2024-07-23 10:23:43 +08:00
md5 md5.MD5
2024-09-29 10:25:28 +08:00
uploadTokenTTL time.Duration
2024-07-23 10:23:43 +08:00
}
type PutRet struct {
Key string `json:"key"`
Hash string `json:"hash"`
Fsize string `json:"fsize"`
Fname string `json:"fname"`
Ext string `json:"ext"`
Unique string `json:"unique"`
User string `json:"user"`
}
2024-08-06 10:15:56 +08:00
func New(accessKey, secretKey, bucket, domain, securityKey string) QiNiu {
2024-09-29 10:25:28 +08:00
cred := credentials.NewCredentials(accessKey, secretKey)
objectsManager := objects.NewObjectsManager(&objects.ObjectsManagerOptions{
Options: http_client.Options{Credentials: cred},
})
2024-07-23 10:23:43 +08:00
return &qiNiu{
bucket: bucket,
domain: domain,
securityKey: securityKey,
2024-09-29 10:25:28 +08:00
credentials: cred,
bucketManager: objectsManager.Bucket(bucket),
2024-07-23 10:23:43 +08:00
md5: md5.New(),
2024-09-29 10:25:28 +08:00
uploadTokenTTL: time.Second * 3600,
2024-07-23 10:23:43 +08:00
}
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) SetDefaultUploadTokenTTL(duration time.Duration) {
q.uploadTokenTTL = duration
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) GetUploadToken() (string, error) {
putPolicy, err := uptoken.NewPutPolicy(q.bucket, time.Now().Add(q.uploadTokenTTL))
if err != nil {
return "", err
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
return uptoken.NewSigner(putPolicy, q.credentials).GetUpToken(context.Background())
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) GetCallbackUploadToken(callbackURL string) (string, error) {
putPolicy, err := uptoken.NewPutPolicy(q.bucket, time.Now().Add(q.uploadTokenTTL))
if err != nil {
return "", err
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
putPolicy.SetCallbackUrl(callbackURL).
SetCallbackBody(`{"key":"$(key)","hash":"$(etag)","fname":"$(fname)","fsize":"$(fsize)","ext":"$(ext)","unique":"$(x:unique)","user":"$(x:user)"}`).
SetCallbackBodyType("application/json")
return uptoken.NewSigner(putPolicy, q.credentials).GetUpToken(context.Background())
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) TimestampSecuritySign(urlStr string, ttl time.Duration) (string, error) {
deadline := time.Now().Add(ttl).Unix()
tUrl, err := cdn.CreateTimestampAntileechURL(urlStr, q.securityKey, deadline)
if err != nil {
return "", err
}
return tUrl, nil
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) UploadFile(key, localFile, callbackURL string) (*PutRet, error) {
putPolicy, err := uptoken.NewPutPolicy(q.bucket, time.Now().Add(q.uploadTokenTTL))
if err != nil {
return nil, err
}
putPolicy.SetCallbackUrl(callbackURL).
SetCallbackBody(`{"key":"$(key)","hash":"$(etag)","fname":"$(fname)","fsize":"$(fsize)","ext":"$(ext)","unique":"$(x:unique)","user":"$(x:user)"}`).
SetCallbackBodyType("application/json")
2024-07-23 10:23:43 +08:00
2024-09-29 10:25:28 +08:00
ret := &PutRet{}
2024-07-23 10:23:43 +08:00
filename := path.Base(key)
fileSuffix := path.Ext(key)
filePrefix := filename[0 : len(filename)-len(fileSuffix)]
2024-09-29 10:25:28 +08:00
uploadManager := uploader.NewUploadManager(&uploader.UploadManagerOptions{})
err = uploadManager.UploadFile(context.Background(), localFile, &uploader.ObjectOptions{
UpToken: uptoken.NewSigner(putPolicy, q.credentials),
ObjectName: &key,
CustomVars: map[string]string{
"unique": filePrefix,
"user": "api",
2024-07-23 10:23:43 +08:00
},
2024-09-29 10:25:28 +08:00
}, ret)
2024-07-23 10:23:43 +08:00
if err != nil {
return nil, err
}
return ret, nil
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) GetPrivateURL(key string, ttl time.Duration) (string, error) {
urlsProvider := downloader.SignURLsProvider(
downloader.NewStaticDomainBasedURLsProvider([]string{q.domain}),
downloader.NewCredentialsSigner(q.credentials),
&downloader.SignOptions{
TTL: ttl,
})
iter, err := urlsProvider.GetURLsIter(context.Background(), key, &downloader.GenerateOptions{BucketName: q.bucket})
if err != nil {
return "", err
}
res := url.URL{}
peek, err := iter.Peek(&res)
if err != nil {
return "", err
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
if peek {
return res.String(), nil
}
return "", errors.New("get private url false")
}
2024-07-23 10:23:43 +08:00
2024-09-29 10:25:28 +08:00
func (q *qiNiu) VerifyCallback(req *http.Request) (bool, error) {
return q.credentials.VerifyCallback(req)
}
2024-07-23 10:23:43 +08:00
2024-09-29 10:25:28 +08:00
func (q *qiNiu) GetFileInfo(key string) (*objects.ObjectDetails, error) {
objectInfo, err := q.bucketManager.Object(key).Stat().Call(context.Background())
2024-07-23 10:23:43 +08:00
if err != nil {
return nil, err
}
2024-09-29 10:25:28 +08:00
return objectInfo, nil
2024-07-23 10:23:43 +08:00
}
func (q *qiNiu) DelFile(key string) error {
2024-09-29 10:25:28 +08:00
err := q.bucketManager.Object(key).Delete().Call(context.Background())
2024-07-23 10:23:43 +08:00
if err != nil {
return err
}
return nil
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) ListFiles(keyPrefix, marker string, limit uint64) ([]objects.ObjectDetails, error) {
iter := q.bucketManager.List(context.Background(), &objects.ListObjectsOptions{
Limit: &limit,
Prefix: keyPrefix,
Marker: marker,
})
defer func() {
_ = iter.Close()
}()
objectInfos := make([]objects.ObjectDetails, 0)
var objectInfo objects.ObjectDetails
for iter.Next(&objectInfo) {
objectInfos = append(objectInfos, objectInfo)
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
if err := iter.Error(); err != nil {
return nil, err
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
return objectInfos, nil
2024-07-23 10:23:43 +08:00
}
2024-09-29 10:25:28 +08:00
func (q *qiNiu) GetFileHash(path string, qhash Qhash) (hash string, err error) {
sign, err := q.TimestampSecuritySign(path, time.Second*5)
if err != nil {
return "", err
2024-07-23 10:23:43 +08:00
}
2024-08-06 10:04:41 +08:00
addr := fmt.Sprintf("%s/%s?%s&qhash/%s", strings.TrimRight(q.domain, "/"), path, sign, qhash)
2024-07-23 10:23:43 +08:00
resp, err := http.Get(addr)
if err != nil {
return "", err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return "", errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return gjson.GetBytes(body, "hash").String(), nil
}