Skip to content

Commit 866d4f4

Browse files
committed
feat(strm): add driver-level sign expiry and rotate action
- add SignExpireHours for STRM-specific sign duration - add RotateSignNow to trigger immediate local STRM rewrite - auto reset rotate flag after scheduling background rotation
1 parent 5852a81 commit 866d4f4

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

drivers/strm/driver.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/alist-org/alist/v3/internal/errs"
1212
"github.com/alist-org/alist/v3/internal/fs"
1313
"github.com/alist-org/alist/v3/internal/model"
14+
"github.com/alist-org/alist/v3/internal/op"
15+
log "github.com/sirupsen/logrus"
1416
)
1517

1618
type Strm struct {
@@ -70,6 +72,20 @@ func (d *Strm) Init(ctx context.Context) error {
7072
if d.SaveLocalMode == "" {
7173
d.SaveLocalMode = SaveLocalInsertMode
7274
}
75+
if d.SignExpireHours < 0 {
76+
d.SignExpireHours = 0
77+
}
78+
if d.RotateSignNow {
79+
d.RotateSignNow = false
80+
op.MustSaveDriverStorage(d)
81+
if d.SaveStrmToLocal && strings.TrimSpace(d.SaveStrmLocalPath) != "" {
82+
go func() {
83+
log.Infof("strm: start rotating signs for [%s]", d.MountPath)
84+
d.rotateAllLocal(context.Background())
85+
log.Infof("strm: finished rotating signs for [%s]", d.MountPath)
86+
}()
87+
}
88+
}
7389
return nil
7490
}
7591

@@ -159,6 +175,36 @@ func (d *Strm) listVirtualRoots() []model.Obj {
159175
return objs
160176
}
161177

178+
func (d *Strm) rotateAllLocal(ctx context.Context) {
179+
for alias, roots := range d.aliases {
180+
virtualRoot := "/"
181+
if !d.autoFlatten {
182+
virtualRoot = "/" + alias
183+
}
184+
for _, realRoot := range roots {
185+
d.walkAndSync(ctx, virtualRoot, realRoot)
186+
}
187+
}
188+
}
189+
190+
func (d *Strm) walkAndSync(ctx context.Context, virtualDir, realDir string) {
191+
objs, err := fs.List(ctx, realDir, &fs.ListArgs{NoLog: true, Refresh: true})
192+
if err != nil {
193+
log.Warnf("strm: rotate list failed %s: %v", realDir, err)
194+
return
195+
}
196+
mapped := d.mapListedObjects(ctx, realDir, objs)
197+
d.syncLocalDirWithMode(ctx, virtualDir, mapped, SaveLocalUpdateMode)
198+
for _, obj := range objs {
199+
if !obj.IsDir() {
200+
continue
201+
}
202+
childVirtual := stdpath.Join(virtualDir, obj.GetName())
203+
childReal := stdpath.Join(realDir, obj.GetName())
204+
d.walkAndSync(ctx, childVirtual, childReal)
205+
}
206+
}
207+
162208
func (d *Strm) mapListedObjects(ctx context.Context, realDir string, listed []model.Obj) []model.Obj {
163209
ret := make([]model.Obj, 0, len(listed))
164210
for _, obj := range listed {

drivers/strm/meta.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type Addition struct {
2020
EncodePath bool `json:"encodePath" default:"true" required:"true" help:"Encode path in strm content"`
2121
WithoutUrl bool `json:"withoutUrl" default:"false" help:"Generate path-only strm content"`
2222
WithSign bool `json:"withSign" default:"false" help:"Append sign query to generated URL"`
23+
SignExpireHours int `json:"SignExpireHours" type:"number" default:"0" help:"Driver-level sign expiration in hours. 0 uses global link_expiration"`
24+
RotateSignNow bool `json:"RotateSignNow" type:"bool" default:"false" help:"Set true and save to rotate signs now (rewrite local STRM), then auto reset to false"`
2325
SaveStrmToLocal bool `json:"SaveStrmToLocal" default:"false" help:"Save generated files to local disk"`
2426
SaveStrmLocalPath string `json:"SaveStrmLocalPath" type:"text" help:"Local path for generated files"`
2527
SaveLocalMode string `json:"SaveLocalMode" type:"select" help:"Local save mode" options:"insert,update,sync" default:"insert"`

drivers/strm/util.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"path/filepath"
1212
"sort"
1313
"strings"
14+
"time"
1415

1516
"github.com/alist-org/alist/v3/drivers/base"
1617
"github.com/alist-org/alist/v3/internal/fs"
@@ -128,7 +129,7 @@ func (d *Strm) buildStrmLine(ctx context.Context, realPath string) string {
128129
if strings.Contains(pathPart, "?") {
129130
sep = "&"
130131
}
131-
pathPart += sep + "sign=" + sign.Sign(realPath)
132+
pathPart += sep + "sign=" + d.generateSign(realPath)
132133
}
133134
joined := stdpath.Join(d.normalizedPrefix, pathPart)
134135
if !strings.HasPrefix(joined, "/") {
@@ -170,13 +171,17 @@ func (d *Strm) linkRealFile(ctx context.Context, realPath string, args model.Lin
170171
if api == "" {
171172
api = common.GetApiUrl(nil)
172173
}
173-
return &model.Link{URL: fmt.Sprintf("%s/p%s?sign=%s", api, utils.EncodePath(realPath, true), sign.Sign(realPath))}, nil
174+
return &model.Link{URL: fmt.Sprintf("%s/p%s?sign=%s", api, utils.EncodePath(realPath, true), d.generateSign(realPath))}, nil
174175
}
175176
link, _, linkErr := op.Link(ctx, storage, actualPath, args)
176177
return link, linkErr
177178
}
178179

179180
func (d *Strm) syncLocalDir(ctx context.Context, virtualDir string, objs []model.Obj) {
181+
d.syncLocalDirWithMode(ctx, virtualDir, objs, d.normalizedMode)
182+
}
183+
184+
func (d *Strm) syncLocalDirWithMode(ctx context.Context, virtualDir string, objs []model.Obj, mode string) {
180185
if !d.SaveStrmToLocal || strings.TrimSpace(d.SaveStrmLocalPath) == "" {
181186
return
182187
}
@@ -204,12 +209,12 @@ func (d *Strm) syncLocalDir(ctx context.Context, virtualDir string, objs []model
204209
log.Warnf("strm: build local payload failed %s: %v", localPath, err)
205210
continue
206211
}
207-
if err = d.writeLocal(localPath, payload); err != nil {
212+
if err = d.writeLocal(localPath, payload, mode); err != nil {
208213
log.Warnf("strm: write local failed %s: %v", localPath, err)
209214
}
210215
}
211216

212-
if d.normalizedMode == SaveLocalSyncMode {
217+
if mode == SaveLocalSyncMode {
213218
d.syncDeleteExtras(localDir, expected)
214219
}
215220
}
@@ -259,19 +264,19 @@ func readLinkBytes(ctx context.Context, link *model.Link) ([]byte, error) {
259264
return io.ReadAll(res.RawBody())
260265
}
261266

262-
func (d *Strm) writeLocal(path string, payload []byte) error {
263-
if d.normalizedMode == SaveLocalInsertMode && utils.Exists(path) {
267+
func (d *Strm) writeLocal(path string, payload []byte, mode string) error {
268+
if mode == SaveLocalInsertMode && utils.Exists(path) {
264269
return nil
265270
}
266271
if st, err := os.Stat(path); err == nil && st.IsDir() {
267-
if d.normalizedMode != SaveLocalSyncMode {
272+
if mode != SaveLocalSyncMode {
268273
return nil
269274
}
270275
if err = os.RemoveAll(path); err != nil {
271276
return err
272277
}
273278
}
274-
if d.normalizedMode != SaveLocalInsertMode {
279+
if mode != SaveLocalInsertMode {
275280
if old, err := os.ReadFile(path); err == nil {
276281
if bytes.Equal(old, payload) {
277282
return nil
@@ -303,3 +308,10 @@ func (d *Strm) syncDeleteExtras(localDir string, expected map[string]bool) {
303308
}
304309
}
305310
}
311+
312+
func (d *Strm) generateSign(path string) string {
313+
if d.SignExpireHours > 0 {
314+
return sign.WithDuration(path, time.Duration(d.SignExpireHours)*time.Hour)
315+
}
316+
return sign.Sign(path)
317+
}

0 commit comments

Comments
 (0)