Skip to content

Commit 1c0ad37

Browse files
committed
feat: enhance storage client with URL handler and public base configuration
Signed-off-by: tbxark <[email protected]>
1 parent acce8be commit 1c0ad37

File tree

10 files changed

+257
-157
lines changed

10 files changed

+257
-157
lines changed

cache/badgerdb/database.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ func NewDatabase(config *Config) (*Database, error) {
2626

2727
func (d *Database) Set(ctx context.Context, key string, val []byte, expiration time.Duration) error {
2828
return d.db.Update(func(txn *badger.Txn) error {
29-
return txn.Set([]byte(key), val)
29+
entry := badger.NewEntry([]byte(key), val)
30+
if expiration > 0 {
31+
entry.WithTTL(expiration)
32+
}
33+
return txn.SetEntry(entry)
3034
})
3135
}
3236

@@ -58,8 +62,11 @@ func (d *Database) Del(ctx context.Context, key string) error {
5862
func (d *Database) MultiSet(ctx context.Context, valMap map[string][]byte, expiration time.Duration) error {
5963
return d.db.Update(func(txn *badger.Txn) error {
6064
for k, v := range valMap {
61-
err := txn.SetEntry(badger.NewEntry([]byte(k), v).WithTTL(expiration))
62-
if err != nil {
65+
entry := badger.NewEntry([]byte(k), v)
66+
if expiration > 0 {
67+
entry.WithTTL(expiration)
68+
}
69+
if err := txn.SetEntry(entry); err != nil {
6370
return err
6471
}
6572
}

cache/cache.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
)
88

99
type Cache[S any] interface {
10+
// Set sets the value for the given key with an expiration time, if expiration is -1, never expires
1011
Set(ctx context.Context, key string, val S, expiration time.Duration) error
1112
Get(ctx context.Context, key string) (*S, error)
1213
Del(ctx context.Context, key string) error

layout/cmd/app/wire_gen.go

+12-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

layout/go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4
152152
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
153153
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
154154
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
155+
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
156+
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
155157
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
156158
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
157159
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
@@ -163,6 +165,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
163165
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
164166
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
165167
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
168+
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
169+
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
166170
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
167171
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
168172
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=

layout/internal/config/config.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ func NewEmptyConfig() *Config {
6161
},
6262
},
6363
Storage: &qiniu.Config{
64-
AccessKey: "",
65-
SecretKey: "",
66-
Bucket: "",
67-
Domain: "",
64+
AccessKey: "",
65+
SecretKey: "",
66+
Bucket: "",
67+
PublicBase: "",
6868
},
6969
Bot: &bot.Config{
7070
Token: "",

storage/kvcache/kvcache.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package kvcache
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"github.com/TBXark/sphere/cache"
7+
"github.com/TBXark/sphere/storage"
8+
"github.com/TBXark/sphere/storage/urlhandler"
9+
"io"
10+
"os"
11+
)
12+
13+
var _ storage.Storage = (*Client)(nil)
14+
15+
type Config struct {
16+
PublicBase string `json:"public_base" yaml:"public_base"`
17+
}
18+
19+
type Client struct {
20+
*urlhandler.Handler
21+
config *Config
22+
cache cache.ByteCache
23+
}
24+
25+
func NewClient(config *Config, cache cache.ByteCache) (*Client, error) {
26+
handler, err := urlhandler.NewHandler(config.PublicBase)
27+
if err != nil {
28+
return nil, err
29+
}
30+
return &Client{
31+
Handler: handler,
32+
config: config,
33+
cache: cache,
34+
}, nil
35+
}
36+
37+
func (c *Client) UploadFile(ctx context.Context, file io.Reader, size int64, key string) (string, error) {
38+
all, err := io.ReadAll(file)
39+
if err != nil {
40+
return "", err
41+
}
42+
err = c.cache.Set(ctx, key, all, -1)
43+
if err != nil {
44+
return "", err
45+
}
46+
return c.GenerateURL(key), nil
47+
}
48+
49+
func (c *Client) UploadLocalFile(ctx context.Context, file string, key string) (string, error) {
50+
raw, err := os.ReadFile(file)
51+
if err != nil {
52+
return "", err
53+
}
54+
err = c.cache.Set(ctx, key, raw, -1)
55+
if err != nil {
56+
return "", err
57+
}
58+
return c.GenerateURL(key), nil
59+
}
60+
61+
func (c *Client) DownloadFile(ctx context.Context, key string) (io.ReadCloser, error) {
62+
data, err := c.cache.Get(ctx, key)
63+
if err != nil {
64+
return nil, err
65+
}
66+
if data == nil {
67+
return nil, os.ErrNotExist
68+
}
69+
return io.NopCloser(bytes.NewReader(*data)), nil
70+
}
71+
72+
func (c *Client) GenerateUploadToken(fileName string, dir string, nameBuilder func(filename string, dir ...string) string) ([3]string, error) {
73+
key := nameBuilder(fileName, dir)
74+
return [3]string{
75+
"",
76+
key,
77+
c.GenerateURL(key),
78+
}, nil
79+
}

storage/qiniu/qiniu.go

+20-80
Original file line numberDiff line numberDiff line change
@@ -5,112 +5,52 @@ import (
55
"crypto/md5"
66
"encoding/hex"
77
"fmt"
8+
"github.com/TBXark/sphere/storage/urlhandler"
89
"github.com/qiniu/go-sdk/v7/auth/qbox"
910
"github.com/qiniu/go-sdk/v7/storage"
1011
"io"
1112
"net/url"
1213
"path"
13-
"strconv"
1414
"strings"
1515
)
1616

17-
var (
18-
ErrNotQiniuHost = fmt.Errorf("not qiniu host")
19-
)
20-
2117
type Config struct {
2218
AccessKey string `json:"access_key" yaml:"access_key"`
2319
SecretKey string `json:"secret_key" yaml:"secret_key"`
24-
Bucket string `json:"bucket" yaml:"bucket"`
25-
Dir string `json:"dir" yaml:"dir"`
26-
Domain string `json:"domain" yaml:"domain"`
27-
Host string `json:"host" yaml:"host"`
20+
21+
Bucket string `json:"bucket" yaml:"bucket"`
22+
Dir string `json:"dir" yaml:"dir"`
23+
24+
PublicBase string `json:"public_base" yaml:"public_base"`
2825
}
2926

3027
type Client struct {
28+
*urlhandler.Handler
3129
config *Config
3230
mac *qbox.Mac
3331
}
3432

35-
func NewClient(config *Config) *Client {
36-
config.Domain = strings.TrimSuffix(config.Domain, "/")
37-
if config.Host == "" {
38-
u, err := url.Parse(config.Domain)
39-
if err == nil {
40-
config.Host = u.Host
41-
}
33+
func NewClient(config *Config) (*Client, error) {
34+
handler, err := urlhandler.NewHandler(config.PublicBase)
35+
if err != nil {
36+
return nil, err
4237
}
4338
mac := qbox.NewMac(config.AccessKey, config.SecretKey)
4439
return &Client{
45-
config: config,
46-
mac: mac,
47-
}
48-
}
49-
50-
func (n *Client) hasHttpScheme(uri string) bool {
51-
return strings.HasPrefix(uri, "http://") || strings.HasPrefix(uri, "https://")
52-
}
53-
54-
func (n *Client) GenerateURL(key string) string {
55-
if key == "" {
56-
return ""
57-
}
58-
if n.hasHttpScheme(key) {
59-
return key
60-
}
61-
buf := strings.Builder{}
62-
buf.WriteString(strings.TrimSuffix(n.config.Domain, "/"))
63-
buf.WriteString("/")
64-
buf.WriteString(strings.TrimPrefix(key, "/"))
65-
return buf.String()
40+
Handler: handler,
41+
config: config,
42+
mac: mac,
43+
}, nil
6644
}
6745

6846
func (n *Client) GenerateImageURL(key string, width int) string {
69-
// 判断是不是已经拼接了 ?imageView2 参数
70-
if strings.Contains(key, "?imageView2") {
71-
// 从URL中提取key
72-
key = n.ExtractKeyFromURL(key)
73-
}
74-
if key == "" {
75-
return ""
76-
}
77-
return n.GenerateURL(key) + "?imageView2/2/w/" + strconv.Itoa(width) + "/q/75"
78-
}
79-
80-
func (n *Client) GenerateURLs(keys []string) []string {
81-
urls := make([]string, len(keys))
82-
for i, key := range keys {
83-
urls[i] = n.GenerateURL(key)
84-
}
85-
return urls
86-
}
87-
88-
func (n *Client) ExtractKeyFromURLWithMode(uri string, strict bool) (string, error) {
89-
if uri == "" {
90-
return "", nil
91-
}
92-
// 不是 http 或者 https 开头的直接返回
93-
if !n.hasHttpScheme(uri) {
94-
return strings.TrimPrefix(uri, "/"), nil
95-
}
96-
// 解析URL
97-
u, err := url.Parse(uri)
47+
uri := n.GenerateURL(key)
48+
res, err := url.Parse(uri)
9849
if err != nil {
99-
return "", nil
50+
return uri
10051
}
101-
// 不是以CDN域名开头的直接返回或者报错
102-
if u.Host != n.config.Host {
103-
if strict {
104-
return "", ErrNotQiniuHost
105-
}
106-
return uri, nil
107-
}
108-
return strings.TrimPrefix(u.Path, "/"), nil
109-
}
110-
111-
func (n *Client) ExtractKeyFromURL(uri string) string {
112-
key, _ := n.ExtractKeyFromURLWithMode(uri, true)
113-
return key
52+
res.RawQuery = fmt.Sprintf("imageView2/2/w/%d/q/75", width)
53+
return res.String()
11454
}
11555

11656
func (n *Client) GenerateUploadToken(fileName string, dir string, nameBuilder func(fileName string, dir ...string) string) ([3]string, error) {

0 commit comments

Comments
 (0)