feat(storage): 实现本地存储功能,包括文件上传和下载接口

This commit is contained in:
2025-12-30 17:14:03 +08:00
parent 452cdc3f4f
commit b969218208
10 changed files with 291 additions and 27 deletions

View File

@@ -0,0 +1,8 @@
package storage
type Config struct {
Type string `json:"type" yaml:"type" toml:"type"` // local, s3
LocalPath string `json:"local_path" yaml:"local_path" toml:"local_path"` // for local
Secret string `json:"secret" yaml:"secret" toml:"secret"` // for signing
BaseURL string `json:"base_url" yaml:"base_url" toml:"base_url"` // public url prefix
}

View File

@@ -0,0 +1,74 @@
package storage
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/url"
"strconv"
"time"
"go.ipao.vip/atom/container"
"go.ipao.vip/atom/opt"
)
func Provide(opts ...opt.Option) error {
o := opt.New(opts...)
var config Config
if err := o.UnmarshalConfig(&config); err != nil {
return err
}
return container.Container.Provide(func() (*Storage, error) {
return &Storage{Config: &config}, nil
}, o.DiOptions()...)
}
type Storage struct {
Config *Config
}
func (s *Storage) SignURL(method, key string, expires time.Duration) (string, error) {
exp := time.Now().Add(expires).Unix()
sign := s.signature(method, key, exp)
baseURL := s.Config.BaseURL
// Ensure BaseURL doesn't end with slash if we add one
// Simplified: assume standard /v1/storage prefix in BaseURL or append it
// We'll append /<key>
u, err := url.Parse(baseURL + "/" + key)
if err != nil {
return "", err
}
q := u.Query()
q.Set("expires", strconv.FormatInt(exp, 10))
q.Set("sign", sign)
u.RawQuery = q.Encode()
return u.String(), nil
}
func (s *Storage) Verify(method, key, expStr, sign string) error {
exp, err := strconv.ParseInt(expStr, 10, 64)
if err != nil {
return fmt.Errorf("invalid expiry")
}
if time.Now().Unix() > exp {
return fmt.Errorf("expired")
}
expected := s.signature(method, key, exp)
if !hmac.Equal([]byte(expected), []byte(sign)) {
return fmt.Errorf("invalid signature")
}
return nil
}
func (s *Storage) signature(method, key string, exp int64) string {
str := fmt.Sprintf("%s\n%s\n%d", method, key, exp)
h := hmac.New(sha256.New, []byte(s.Config.Secret))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}