mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-10-10 21:13:10 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0857478516 | |||
| 66d9809057 | |||
| db8a7e8caf |
@@ -17,7 +17,6 @@ func Init() {
|
|||||||
bootstrap.Log()
|
bootstrap.Log()
|
||||||
bootstrap.InitDB()
|
bootstrap.InitDB()
|
||||||
data.InitData()
|
data.InitData()
|
||||||
bootstrap.InitPlugins()
|
|
||||||
bootstrap.InitStreamLimit()
|
bootstrap.InitStreamLimit()
|
||||||
bootstrap.InitIndex()
|
bootstrap.InitIndex()
|
||||||
bootstrap.InitUpgradePatch()
|
bootstrap.InitUpgradePatch()
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ func (d *Pan123) GetAddition() driver.Additional {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Pan123) Init(ctx context.Context) error {
|
func (d *Pan123) Init(ctx context.Context) error {
|
||||||
_, err := d.Request(UserInfo, http.MethodGet, nil, nil)
|
_, err := d.Request(UserInfo, http.MethodGet, func(req *resty.Request) {
|
||||||
|
req.SetHeader("platform", "web")
|
||||||
|
}, nil)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type Addition struct {
|
|||||||
//OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
|
//OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
UploadThread int `json:"UploadThread" type:"number" default:"3" help:"the threads of upload"`
|
UploadThread int `json:"UploadThread" type:"number" default:"3" help:"the threads of upload"`
|
||||||
|
Platform string `json:"platform" type:"string" default:"web" help:"the platform header value, sent with API requests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = driver.Config{
|
var config = driver.Config{
|
||||||
|
|||||||
+1
-1
@@ -203,7 +203,7 @@ do:
|
|||||||
"referer": "https://www.123pan.com/",
|
"referer": "https://www.123pan.com/",
|
||||||
"authorization": "Bearer " + d.AccessToken,
|
"authorization": "Bearer " + d.AccessToken,
|
||||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) openlist-client",
|
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) openlist-client",
|
||||||
"platform": "web",
|
"platform": d.Platform,
|
||||||
"app-version": "3",
|
"app-version": "3",
|
||||||
//"user-agent": base.UserAgent,
|
//"user-agent": base.UserAgent,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/OpenListTeam/OpenList/v4/internal/stream"
|
"github.com/OpenListTeam/OpenList/v4/internal/stream"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||||
"github.com/OpenListTeam/OpenList/v4/server/common"
|
"github.com/OpenListTeam/OpenList/v4/server/common"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Strm struct {
|
type Strm struct {
|
||||||
@@ -40,6 +41,9 @@ func (d *Strm) Init(ctx context.Context) error {
|
|||||||
if d.Paths == "" {
|
if d.Paths == "" {
|
||||||
return errors.New("paths is required")
|
return errors.New("paths is required")
|
||||||
}
|
}
|
||||||
|
if d.SaveStrmToLocal && len(d.SaveStrmLocalPath) <= 0 {
|
||||||
|
return errors.New("SaveStrmLocalPath is required")
|
||||||
|
}
|
||||||
d.pathMap = make(map[string][]string)
|
d.pathMap = make(map[string][]string)
|
||||||
for _, path := range strings.Split(d.Paths, "\n") {
|
for _, path := range strings.Split(d.Paths, "\n") {
|
||||||
path = strings.TrimSpace(path)
|
path = strings.TrimSpace(path)
|
||||||
@@ -48,6 +52,11 @@ func (d *Strm) Init(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
k, v := getPair(path)
|
k, v := getPair(path)
|
||||||
d.pathMap[k] = append(d.pathMap[k], v)
|
d.pathMap[k] = append(d.pathMap[k], v)
|
||||||
|
err := InsertStrm(utils.FixAndCleanPath(strings.TrimSpace(path)), d)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert strmTrie error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(d.pathMap) == 1 {
|
if len(d.pathMap) == 1 {
|
||||||
for k := range d.pathMap {
|
for k := range d.pathMap {
|
||||||
@@ -87,6 +96,9 @@ func (d *Strm) Drop(ctx context.Context) error {
|
|||||||
d.pathMap = nil
|
d.pathMap = nil
|
||||||
d.downloadSuffix = nil
|
d.downloadSuffix = nil
|
||||||
d.supportSuffix = nil
|
d.supportSuffix = nil
|
||||||
|
for _, path := range strings.Split(d.Paths, "\n") {
|
||||||
|
RemoveStrm(utils.FixAndCleanPath(strings.TrimSpace(path)), d)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
package strm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/stream"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/tchap/go-patricia/v2/patricia"
|
||||||
|
)
|
||||||
|
|
||||||
|
var strmTrie = patricia.NewTrie()
|
||||||
|
|
||||||
|
func UpdateLocalStrm(ctx context.Context, path string, objs []model.Obj) {
|
||||||
|
path = utils.FixAndCleanPath(path)
|
||||||
|
updateLocal := func(driver *Strm, basePath string, objs []model.Obj) {
|
||||||
|
relParent := strings.TrimPrefix(basePath, driver.MountPath)
|
||||||
|
localParentPath := stdpath.Join(driver.SaveStrmLocalPath, relParent)
|
||||||
|
for _, obj := range objs {
|
||||||
|
localPath := stdpath.Join(localParentPath, obj.GetName())
|
||||||
|
generateStrm(ctx, driver, obj, localPath)
|
||||||
|
}
|
||||||
|
deleteExtraFiles(localParentPath, objs)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = strmTrie.VisitPrefixes(patricia.Prefix(path), func(needPathPrefix patricia.Prefix, item patricia.Item) error {
|
||||||
|
strmDrivers := item.([]*Strm)
|
||||||
|
needPath := string(needPathPrefix)
|
||||||
|
restPath := strings.TrimPrefix(path, needPath)
|
||||||
|
if len(restPath) > 0 && restPath[0] != '/' {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, strmDriver := range strmDrivers {
|
||||||
|
strmObjs, _ := utils.SliceConvert(objs, func(obj model.Obj) (model.Obj, error) {
|
||||||
|
ret := strmDriver.convert2strmObj(ctx, path, obj)
|
||||||
|
return &ret, nil
|
||||||
|
})
|
||||||
|
updateLocal(strmDriver, stdpath.Join(stdpath.Base(needPath), restPath), strmObjs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertStrm(dstPath string, d *Strm) error {
|
||||||
|
prefix := patricia.Prefix(strings.TrimRight(dstPath, "/"))
|
||||||
|
existing := strmTrie.Get(prefix)
|
||||||
|
|
||||||
|
if existing == nil {
|
||||||
|
if !strmTrie.Insert(prefix, []*Strm{d}) {
|
||||||
|
return errors.New("failed to insert strm")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if lst, ok := existing.([]*Strm); ok {
|
||||||
|
strmTrie.Set(prefix, append(lst, d))
|
||||||
|
} else {
|
||||||
|
return errors.New("invalid trie item type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveStrm(dstPath string, d *Strm) {
|
||||||
|
prefix := patricia.Prefix(strings.TrimRight(dstPath, "/"))
|
||||||
|
existing := strmTrie.Get(prefix)
|
||||||
|
if existing == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lst, ok := existing.([]*Strm)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(lst) == 1 && lst[0] == d {
|
||||||
|
strmTrie.Delete(prefix)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, di := range lst {
|
||||||
|
if di == d {
|
||||||
|
newList := append(lst[:i], lst[i+1:]...)
|
||||||
|
strmTrie.Set(prefix, newList)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateStrm(ctx context.Context, driver *Strm, obj model.Obj, localPath string) {
|
||||||
|
link, err := driver.Link(ctx, obj, model.LinkArgs{})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to generate strm of obj %s: failed to link: %v", localPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seekableStream, err := stream.NewSeekableStream(&stream.FileStream{
|
||||||
|
Obj: obj,
|
||||||
|
Ctx: ctx,
|
||||||
|
}, link)
|
||||||
|
if err != nil {
|
||||||
|
_ = link.Close()
|
||||||
|
log.Warnf("failed to generate strm of obj %s: failed to get seekable stream: %v", localPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer seekableStream.Close()
|
||||||
|
file, err := utils.CreateNestedFile(localPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to generate strm of obj %s: failed to create local file: %v", localPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
if _, err := io.Copy(file, seekableStream); err != nil {
|
||||||
|
log.Warnf("failed to generate strm of obj %s: copy failed: %v", localPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteExtraFiles(localPath string, objs []model.Obj) {
|
||||||
|
localFiles, err := getLocalFiles(localPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to read local files from %s: %v", localPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
objsSet := make(map[string]struct{})
|
||||||
|
for _, obj := range objs {
|
||||||
|
if obj.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
objsSet[stdpath.Join(localPath, obj.GetName())] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, localFile := range localFiles {
|
||||||
|
if _, exists := objsSet[localFile]; !exists {
|
||||||
|
err := os.Remove(localFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to delete file: %s, error: %v\n", localFile, err)
|
||||||
|
} else {
|
||||||
|
log.Infof("Deleted file %s", localFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocalFiles(localPath string) ([]string, error) {
|
||||||
|
var files []string
|
||||||
|
entries, err := os.ReadDir(localPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() {
|
||||||
|
files = append(files, stdpath.Join(localPath, entry.Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
op.RegisterObjsUpdateHook(UpdateLocalStrm)
|
||||||
|
}
|
||||||
@@ -11,7 +11,9 @@ type Addition struct {
|
|||||||
FilterFileTypes string `json:"filterFileTypes" type:"text" default:"strm" required:"false" help:"Supports suffix name of strm file"`
|
FilterFileTypes string `json:"filterFileTypes" type:"text" default:"strm" required:"false" help:"Supports suffix name of strm file"`
|
||||||
DownloadFileTypes string `json:"downloadFileTypes" type:"text" default:"ass" required:"false" help:"Files need to download with strm (usally subtitles)"`
|
DownloadFileTypes string `json:"downloadFileTypes" type:"text" default:"ass" required:"false" help:"Files need to download with strm (usally subtitles)"`
|
||||||
EncodePath bool `json:"encodePath" default:"true" required:"true" help:"encode the path in the strm file"`
|
EncodePath bool `json:"encodePath" default:"true" required:"true" help:"encode the path in the strm file"`
|
||||||
LocalModel bool `json:"localModel" default:"false" help:"enable local mode"`
|
WithoutUrl bool `json:"withoutUrl" default:"false" help:"strm file content without URL prefix"`
|
||||||
|
SaveStrmToLocal bool `json:"SaveStrmToLocal" default:"false" help:"save strm file locally"`
|
||||||
|
SaveStrmLocalPath string `json:"SaveStrmLocalPath" type:"text" help:"save strm file local path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = driver.Config{
|
var config = driver.Config{
|
||||||
|
|||||||
+23
-19
@@ -61,6 +61,23 @@ func (d *Strm) list(ctx context.Context, dst, sub string, args *fs.ListArgs) ([]
|
|||||||
|
|
||||||
var validObjs []model.Obj
|
var validObjs []model.Obj
|
||||||
for _, obj := range objs {
|
for _, obj := range objs {
|
||||||
|
objRes := d.convert2strmObj(ctx, reqPath, obj)
|
||||||
|
thumb, ok := model.GetThumb(obj)
|
||||||
|
if !ok {
|
||||||
|
validObjs = append(validObjs, &objRes)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
validObjs = append(validObjs, &model.ObjThumb{
|
||||||
|
Object: objRes,
|
||||||
|
Thumbnail: model.Thumbnail{
|
||||||
|
Thumbnail: thumb,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return validObjs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Strm) convert2strmObj(ctx context.Context, reqPath string, obj model.Obj) model.Object {
|
||||||
id, name, path := "", obj.GetName(), ""
|
id, name, path := "", obj.GetName(), ""
|
||||||
size := int64(0)
|
size := int64(0)
|
||||||
if !obj.IsDir() {
|
if !obj.IsDir() {
|
||||||
@@ -73,10 +90,10 @@ func (d *Strm) list(ctx context.Context, dst, sub string, args *fs.ListArgs) ([]
|
|||||||
} else if _, ok := d.downloadSuffix[ext]; ok {
|
} else if _, ok := d.downloadSuffix[ext]; ok {
|
||||||
size = obj.GetSize()
|
size = obj.GetSize()
|
||||||
} else {
|
} else {
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
objRes := model.Object{
|
return model.Object{
|
||||||
ID: id,
|
ID: id,
|
||||||
Path: path,
|
Path: path,
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -84,21 +101,6 @@ func (d *Strm) list(ctx context.Context, dst, sub string, args *fs.ListArgs) ([]
|
|||||||
Modified: obj.ModTime(),
|
Modified: obj.ModTime(),
|
||||||
IsFolder: obj.IsDir(),
|
IsFolder: obj.IsDir(),
|
||||||
}
|
}
|
||||||
|
|
||||||
thumb, ok := model.GetThumb(obj)
|
|
||||||
if !ok {
|
|
||||||
validObjs = append(validObjs, &objRes)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
validObjs = append(validObjs, &model.ObjThumb{
|
|
||||||
Object: objRes,
|
|
||||||
Thumbnail: model.Thumbnail{
|
|
||||||
Thumbnail: thumb,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return validObjs, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Strm) getLink(ctx context.Context, path string) string {
|
func (d *Strm) getLink(ctx context.Context, path string) string {
|
||||||
@@ -110,7 +112,7 @@ func (d *Strm) getLink(ctx context.Context, path string) string {
|
|||||||
signPath := sign.Sign(path)
|
signPath := sign.Sign(path)
|
||||||
finalPath = fmt.Sprintf("%s?sign=%s", finalPath, signPath)
|
finalPath = fmt.Sprintf("%s?sign=%s", finalPath, signPath)
|
||||||
}
|
}
|
||||||
if d.LocalModel {
|
if d.WithoutUrl {
|
||||||
return finalPath
|
return finalPath
|
||||||
}
|
}
|
||||||
apiUrl := d.SiteUrl
|
apiUrl := d.SiteUrl
|
||||||
@@ -119,7 +121,9 @@ func (d *Strm) getLink(ctx context.Context, path string) string {
|
|||||||
} else {
|
} else {
|
||||||
apiUrl = common.GetApiUrl(ctx)
|
apiUrl = common.GetApiUrl(ctx)
|
||||||
}
|
}
|
||||||
|
if !strings.HasPrefix(finalPath, "/") {
|
||||||
|
finalPath = "/" + finalPath
|
||||||
|
}
|
||||||
return fmt.Sprintf("%s/d%s",
|
return fmt.Sprintf("%s/d%s",
|
||||||
apiUrl,
|
apiUrl,
|
||||||
finalPath)
|
finalPath)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ func (x *Thunder) Init(ctx context.Context) (err error) {
|
|||||||
PackageName: "com.xunlei.downloadprovider",
|
PackageName: "com.xunlei.downloadprovider",
|
||||||
UserAgent: "ANDROID-com.xunlei.downloadprovider/8.31.0.9726 netWorkType/5G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/512000 Oauth2Client/0.9 (Linux 4_14_186-perf-gddfs8vbb238b) (JAVA 0)",
|
UserAgent: "ANDROID-com.xunlei.downloadprovider/8.31.0.9726 netWorkType/5G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/512000 Oauth2Client/0.9 (Linux 4_14_186-perf-gddfs8vbb238b) (JAVA 0)",
|
||||||
DownloadUserAgent: "Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)",
|
DownloadUserAgent: "Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)",
|
||||||
|
Space: x.Space,
|
||||||
refreshCTokenCk: func(token string) {
|
refreshCTokenCk: func(token string) {
|
||||||
x.CaptchaToken = token
|
x.CaptchaToken = token
|
||||||
op.MustSaveDriverStorage(x)
|
op.MustSaveDriverStorage(x)
|
||||||
@@ -167,6 +169,7 @@ func (x *ThunderExpert) Init(ctx context.Context) (err error) {
|
|||||||
UserAgent: x.UserAgent,
|
UserAgent: x.UserAgent,
|
||||||
DownloadUserAgent: x.DownloadUserAgent,
|
DownloadUserAgent: x.DownloadUserAgent,
|
||||||
UseVideoUrl: x.UseVideoUrl,
|
UseVideoUrl: x.UseVideoUrl,
|
||||||
|
Space: x.Space,
|
||||||
|
|
||||||
refreshCTokenCk: func(token string) {
|
refreshCTokenCk: func(token string) {
|
||||||
x.CaptchaToken = token
|
x.CaptchaToken = token
|
||||||
@@ -281,7 +284,7 @@ func (xc *XunLeiCommon) Link(ctx context.Context, file model.Obj, args model.Lin
|
|||||||
_, err := xc.Request(FILE_API_URL+"/{fileID}", http.MethodGet, func(r *resty.Request) {
|
_, err := xc.Request(FILE_API_URL+"/{fileID}", http.MethodGet, func(r *resty.Request) {
|
||||||
r.SetContext(ctx)
|
r.SetContext(ctx)
|
||||||
r.SetPathParam("fileID", file.GetID())
|
r.SetPathParam("fileID", file.GetID())
|
||||||
//r.SetQueryParam("space", "")
|
r.SetQueryParam("space", xc.Space)
|
||||||
}, &lFile)
|
}, &lFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -322,6 +325,7 @@ func (xc *XunLeiCommon) MakeDir(ctx context.Context, parentDir model.Obj, dirNam
|
|||||||
"kind": FOLDER,
|
"kind": FOLDER,
|
||||||
"name": dirName,
|
"name": dirName,
|
||||||
"parent_id": parentDir.GetID(),
|
"parent_id": parentDir.GetID(),
|
||||||
|
"space": xc.Space,
|
||||||
})
|
})
|
||||||
}, nil)
|
}, nil)
|
||||||
return err
|
return err
|
||||||
@@ -333,6 +337,7 @@ func (xc *XunLeiCommon) Move(ctx context.Context, srcObj, dstDir model.Obj) erro
|
|||||||
r.SetBody(&base.Json{
|
r.SetBody(&base.Json{
|
||||||
"to": base.Json{"parent_id": dstDir.GetID()},
|
"to": base.Json{"parent_id": dstDir.GetID()},
|
||||||
"ids": []string{srcObj.GetID()},
|
"ids": []string{srcObj.GetID()},
|
||||||
|
"space": xc.Space,
|
||||||
})
|
})
|
||||||
}, nil)
|
}, nil)
|
||||||
return err
|
return err
|
||||||
@@ -342,7 +347,10 @@ func (xc *XunLeiCommon) Rename(ctx context.Context, srcObj model.Obj, newName st
|
|||||||
_, err := xc.Request(FILE_API_URL+"/{fileID}", http.MethodPatch, func(r *resty.Request) {
|
_, err := xc.Request(FILE_API_URL+"/{fileID}", http.MethodPatch, func(r *resty.Request) {
|
||||||
r.SetContext(ctx)
|
r.SetContext(ctx)
|
||||||
r.SetPathParam("fileID", srcObj.GetID())
|
r.SetPathParam("fileID", srcObj.GetID())
|
||||||
r.SetBody(&base.Json{"name": newName})
|
r.SetBody(&base.Json{
|
||||||
|
"name": newName,
|
||||||
|
"space": xc.Space,
|
||||||
|
})
|
||||||
}, nil)
|
}, nil)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -353,6 +361,7 @@ func (xc *XunLeiCommon) Copy(ctx context.Context, srcObj, dstDir model.Obj) erro
|
|||||||
r.SetBody(&base.Json{
|
r.SetBody(&base.Json{
|
||||||
"to": base.Json{"parent_id": dstDir.GetID()},
|
"to": base.Json{"parent_id": dstDir.GetID()},
|
||||||
"ids": []string{srcObj.GetID()},
|
"ids": []string{srcObj.GetID()},
|
||||||
|
"space": xc.Space,
|
||||||
})
|
})
|
||||||
}, nil)
|
}, nil)
|
||||||
return err
|
return err
|
||||||
@@ -362,6 +371,7 @@ func (xc *XunLeiCommon) Remove(ctx context.Context, obj model.Obj) error {
|
|||||||
_, err := xc.Request(FILE_API_URL+"/{fileID}/trash", http.MethodPatch, func(r *resty.Request) {
|
_, err := xc.Request(FILE_API_URL+"/{fileID}/trash", http.MethodPatch, func(r *resty.Request) {
|
||||||
r.SetContext(ctx)
|
r.SetContext(ctx)
|
||||||
r.SetPathParam("fileID", obj.GetID())
|
r.SetPathParam("fileID", obj.GetID())
|
||||||
|
r.SetQueryParam("space", xc.Space)
|
||||||
r.SetBody("{}")
|
r.SetBody("{}")
|
||||||
}, nil)
|
}, nil)
|
||||||
return err
|
return err
|
||||||
@@ -387,6 +397,7 @@ func (xc *XunLeiCommon) Put(ctx context.Context, dstDir model.Obj, file model.Fi
|
|||||||
"size": file.GetSize(),
|
"size": file.GetSize(),
|
||||||
"hash": gcid,
|
"hash": gcid,
|
||||||
"upload_type": UPLOAD_TYPE_RESUMABLE,
|
"upload_type": UPLOAD_TYPE_RESUMABLE,
|
||||||
|
"space": xc.Space,
|
||||||
})
|
})
|
||||||
}, &resp)
|
}, &resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -430,7 +441,7 @@ func (xc *XunLeiCommon) getFiles(ctx context.Context, folderId string) ([]model.
|
|||||||
_, err := xc.Request(FILE_API_URL, http.MethodGet, func(r *resty.Request) {
|
_, err := xc.Request(FILE_API_URL, http.MethodGet, func(r *resty.Request) {
|
||||||
r.SetContext(ctx)
|
r.SetContext(ctx)
|
||||||
r.SetQueryParams(map[string]string{
|
r.SetQueryParams(map[string]string{
|
||||||
"space": "",
|
"space": xc.Space,
|
||||||
"__type": "drive",
|
"__type": "drive",
|
||||||
"refresh": "true",
|
"refresh": "true",
|
||||||
"__sync": "true",
|
"__sync": "true",
|
||||||
@@ -440,6 +451,17 @@ func (xc *XunLeiCommon) getFiles(ctx context.Context, folderId string) ([]model.
|
|||||||
"limit": "100",
|
"limit": "100",
|
||||||
"filters": `{"phase":{"eq":"PHASE_TYPE_COMPLETE"},"trashed":{"eq":false}}`,
|
"filters": `{"phase":{"eq":"PHASE_TYPE_COMPLETE"},"trashed":{"eq":false}}`,
|
||||||
})
|
})
|
||||||
|
// 获取硬盘挂载目录等
|
||||||
|
if xc.Space != "" {
|
||||||
|
r.SetQueryParamsFromValues(url.Values{
|
||||||
|
"with": []string{
|
||||||
|
"withCategoryDiskMountPath",
|
||||||
|
"withCategoryDriveCachePath",
|
||||||
|
"withCategoryHistoryDownloadPath",
|
||||||
|
"withReadOnlyFS",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}, &fileList)
|
}, &fileList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -576,6 +598,7 @@ func (xc *XunLeiCommon) OfflineDownload(ctx context.Context, fileUrl string, par
|
|||||||
"name": fileName,
|
"name": fileName,
|
||||||
"parent_id": parentDir.GetID(),
|
"parent_id": parentDir.GetID(),
|
||||||
"upload_type": UPLOAD_TYPE_URL,
|
"upload_type": UPLOAD_TYPE_URL,
|
||||||
|
"space": xc.Space,
|
||||||
"url": base.Json{
|
"url": base.Json{
|
||||||
"url": fileUrl,
|
"url": fileUrl,
|
||||||
},
|
},
|
||||||
@@ -602,6 +625,7 @@ func (xc *XunLeiCommon) OfflineList(ctx context.Context, nextPageToken string) (
|
|||||||
"type": "offline",
|
"type": "offline",
|
||||||
"limit": "10000",
|
"limit": "10000",
|
||||||
"page_token": nextPageToken,
|
"page_token": nextPageToken,
|
||||||
|
"space": xc.Space,
|
||||||
})
|
})
|
||||||
}, &resp)
|
}, &resp)
|
||||||
|
|
||||||
@@ -618,6 +642,7 @@ func (xc *XunLeiCommon) DeleteOfflineTasks(ctx context.Context, taskIDs []string
|
|||||||
SetQueryParams(map[string]string{
|
SetQueryParams(map[string]string{
|
||||||
"task_ids": strings.Join(taskIDs, ","),
|
"task_ids": strings.Join(taskIDs, ","),
|
||||||
"delete_files": strconv.FormatBool(deleteFiles),
|
"delete_files": strconv.FormatBool(deleteFiles),
|
||||||
|
"space": xc.Space,
|
||||||
})
|
})
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ type ExpertAddition struct {
|
|||||||
|
|
||||||
//优先使用视频链接代替下载链接
|
//优先使用视频链接代替下载链接
|
||||||
UseVideoUrl bool `json:"use_video_url"`
|
UseVideoUrl bool `json:"use_video_url"`
|
||||||
|
|
||||||
|
Space string `json:"space" default:"" help:"device id for remote device"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录特征,用于判断是否重新登录
|
// 登录特征,用于判断是否重新登录
|
||||||
@@ -80,6 +82,8 @@ type Addition struct {
|
|||||||
CreditKey string `json:"credit_key" help:"credit key,used for login"`
|
CreditKey string `json:"credit_key" help:"credit key,used for login"`
|
||||||
// 登录设备ID
|
// 登录设备ID
|
||||||
DeviceID string `json:"device_id" default:""`
|
DeviceID string `json:"device_id" default:""`
|
||||||
|
|
||||||
|
Space string `json:"space" default:"" help:"device id for remote device"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录特征,用于判断是否重新登录
|
// 登录特征,用于判断是否重新登录
|
||||||
@@ -90,7 +94,6 @@ func (i *Addition) GetIdentity() string {
|
|||||||
var config = driver.Config{
|
var config = driver.Config{
|
||||||
Name: "Thunder",
|
Name: "Thunder",
|
||||||
LocalSort: true,
|
LocalSort: true,
|
||||||
OnlyProxy: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var configExpert = driver.Config{
|
var configExpert = driver.Config{
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ type Common struct {
|
|||||||
UserAgent string
|
UserAgent string
|
||||||
DownloadUserAgent string
|
DownloadUserAgent string
|
||||||
UseVideoUrl bool
|
UseVideoUrl bool
|
||||||
|
Space string
|
||||||
|
|
||||||
// 验证码token刷新成功回调
|
// 验证码token刷新成功回调
|
||||||
refreshCTokenCk func(token string)
|
refreshCTokenCk func(token string)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ require (
|
|||||||
github.com/OpenListTeam/sftpd-openlist v1.0.1
|
github.com/OpenListTeam/sftpd-openlist v1.0.1
|
||||||
github.com/OpenListTeam/tache v0.2.0
|
github.com/OpenListTeam/tache v0.2.0
|
||||||
github.com/OpenListTeam/times v0.1.0
|
github.com/OpenListTeam/times v0.1.0
|
||||||
github.com/OpenListTeam/wazero-wasip2 v0.0.0-20251015145605-cd3a2c9131d9
|
|
||||||
github.com/OpenListTeam/wopan-sdk-go v0.1.5
|
github.com/OpenListTeam/wopan-sdk-go v0.1.5
|
||||||
github.com/ProtonMail/go-crypto v1.3.0
|
github.com/ProtonMail/go-crypto v1.3.0
|
||||||
github.com/SheltonZhu/115driver v1.1.1
|
github.com/SheltonZhu/115driver v1.1.1
|
||||||
@@ -64,7 +63,6 @@ require (
|
|||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5
|
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5
|
||||||
github.com/tchap/go-patricia/v2 v2.3.3
|
github.com/tchap/go-patricia/v2 v2.3.3
|
||||||
github.com/tetratelabs/wazero v1.9.0
|
|
||||||
github.com/u2takey/ffmpeg-go v0.5.0
|
github.com/u2takey/ffmpeg-go v0.5.0
|
||||||
github.com/upyun/go-sdk/v3 v3.0.4
|
github.com/upyun/go-sdk/v3 v3.0.4
|
||||||
github.com/winfsp/cgofuse v1.6.0
|
github.com/winfsp/cgofuse v1.6.0
|
||||||
@@ -194,7 +192,7 @@ require (
|
|||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/bytedance/sonic v1.13.3 // indirect
|
github.com/bytedance/sonic v1.13.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/coreos/go-semver v0.3.1
|
github.com/coreos/go-semver v0.3.1 // indirect
|
||||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||||
@@ -305,5 +303,3 @@ replace github.com/ProtonMail/go-proton-api => github.com/henrybear327/go-proton
|
|||||||
replace github.com/cronokirby/saferith => github.com/Da3zKi7/saferith v0.33.0-fixed
|
replace github.com/cronokirby/saferith => github.com/Da3zKi7/saferith v0.33.0-fixed
|
||||||
|
|
||||||
// replace github.com/OpenListTeam/115-sdk-go => ../../OpenListTeam/115-sdk-go
|
// replace github.com/OpenListTeam/115-sdk-go => ../../OpenListTeam/115-sdk-go
|
||||||
|
|
||||||
replace google.golang.org/genproto => google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822
|
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ github.com/OpenListTeam/tache v0.2.0 h1:Q4MjuyECn0CZCf1ZF91JaVaZTaps1mOTAm8bFj8s
|
|||||||
github.com/OpenListTeam/tache v0.2.0/go.mod h1:qmnZ/VpY2DUlmjg3UoDeNFy/LRqrw0biN3hYEEGc/+A=
|
github.com/OpenListTeam/tache v0.2.0/go.mod h1:qmnZ/VpY2DUlmjg3UoDeNFy/LRqrw0biN3hYEEGc/+A=
|
||||||
github.com/OpenListTeam/times v0.1.0 h1:qknxw+qj5CYKgXAwydA102UEpPcpU8TYNGRmwRyPYpg=
|
github.com/OpenListTeam/times v0.1.0 h1:qknxw+qj5CYKgXAwydA102UEpPcpU8TYNGRmwRyPYpg=
|
||||||
github.com/OpenListTeam/times v0.1.0/go.mod h1:Jx7qen5NCYzKk2w14YuvU48YYMcPa1P9a+EJePC15Pc=
|
github.com/OpenListTeam/times v0.1.0/go.mod h1:Jx7qen5NCYzKk2w14YuvU48YYMcPa1P9a+EJePC15Pc=
|
||||||
github.com/OpenListTeam/wazero-wasip2 v0.0.0-20251015145605-cd3a2c9131d9 h1:yddTD9Fxh6bLMLmG0hSR7Eh6XkoK0RMlE4N1e6/+Iy8=
|
|
||||||
github.com/OpenListTeam/wazero-wasip2 v0.0.0-20251015145605-cd3a2c9131d9/go.mod h1:+BpydPG2cUQHYFwH3/lVmvXyMl/zxHW+XM+XTSzqu2Q=
|
|
||||||
github.com/OpenListTeam/wopan-sdk-go v0.1.5 h1:iKKcVzIqBgtGDbn0QbdWrCazSGxXFmYFyrnFBG+U8dI=
|
github.com/OpenListTeam/wopan-sdk-go v0.1.5 h1:iKKcVzIqBgtGDbn0QbdWrCazSGxXFmYFyrnFBG+U8dI=
|
||||||
github.com/OpenListTeam/wopan-sdk-go v0.1.5/go.mod h1:otynv0CgSNUClPpUgZ44qCZGcMRe0dc83Pkk65xAunI=
|
github.com/OpenListTeam/wopan-sdk-go v0.1.5/go.mod h1:otynv0CgSNUClPpUgZ44qCZGcMRe0dc83Pkk65xAunI=
|
||||||
github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57/go.mod h1:HecWFHognK8GfRDGnFQbW/LiV7A3MX3gZVs45vk5h8I=
|
github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57/go.mod h1:HecWFHognK8GfRDGnFQbW/LiV7A3MX3gZVs45vk5h8I=
|
||||||
@@ -690,8 +688,6 @@ github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 h1:6Y51mutOvRGRx6K
|
|||||||
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow=
|
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow=
|
||||||
github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc=
|
github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc=
|
||||||
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
|
||||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
|
||||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
//go:build !unix && !windows
|
|
||||||
|
|
||||||
package alloc // import "github.com/ncruces/go-sqlite3/internal/alloc"
|
|
||||||
|
|
||||||
import "github.com/tetratelabs/wazero/experimental"
|
|
||||||
|
|
||||||
func NewMemory(cap, max uint64) experimental.LinearMemory {
|
|
||||||
return &sliceMemory{make([]byte, 0, cap)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type sliceMemory struct {
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *sliceMemory) Free() {}
|
|
||||||
|
|
||||||
func (b *sliceMemory) Reallocate(size uint64) []byte {
|
|
||||||
if cap := uint64(cap(b.buf)); size > cap {
|
|
||||||
b.buf = append(b.buf[:cap], make([]byte, size-cap)...)
|
|
||||||
} else {
|
|
||||||
b.buf = b.buf[:size]
|
|
||||||
}
|
|
||||||
return b.buf
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package alloc_test // import "github.com/ncruces/go-sqlite3/internal/alloc"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/alloc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestVirtual(t *testing.T) {
|
|
||||||
defer func() { _ = recover() }()
|
|
||||||
alloc.NewMemory(math.MaxInt+2, math.MaxInt+2)
|
|
||||||
t.Error("want panic")
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
//go:build unix
|
|
||||||
|
|
||||||
package alloc // import "github.com/ncruces/go-sqlite3/internal/alloc"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/experimental"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMemory(cap, max uint64) experimental.LinearMemory {
|
|
||||||
// Round up to the page size.
|
|
||||||
rnd := uint64(unix.Getpagesize() - 1)
|
|
||||||
res := (max + rnd) &^ rnd
|
|
||||||
|
|
||||||
if res > math.MaxInt {
|
|
||||||
// This ensures int(res) overflows to a negative value,
|
|
||||||
// and unix.Mmap returns EINVAL.
|
|
||||||
res = math.MaxUint64
|
|
||||||
}
|
|
||||||
|
|
||||||
com := res
|
|
||||||
prot := unix.PROT_READ | unix.PROT_WRITE
|
|
||||||
if cap < max { // Commit memory only if cap=max.
|
|
||||||
com = 0
|
|
||||||
prot = unix.PROT_NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserve res bytes of address space, to ensure we won't need to move it.
|
|
||||||
// A protected, private, anonymous mapping should not commit memory.
|
|
||||||
b, err := unix.Mmap(-1, 0, int(res), prot, unix.MAP_PRIVATE|unix.MAP_ANON)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return &mmappedMemory{buf: b[:com]}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The slice covers the entire mmapped memory:
|
|
||||||
// - len(buf) is the already committed memory,
|
|
||||||
// - cap(buf) is the reserved address space.
|
|
||||||
type mmappedMemory struct {
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mmappedMemory) Reallocate(size uint64) []byte {
|
|
||||||
com := uint64(len(m.buf))
|
|
||||||
res := uint64(cap(m.buf))
|
|
||||||
if com < size && size <= res {
|
|
||||||
// Grow geometrically, round up to the page size.
|
|
||||||
rnd := uint64(unix.Getpagesize() - 1)
|
|
||||||
new := com + com>>3
|
|
||||||
new = min(max(size, new), res)
|
|
||||||
new = (new + rnd) &^ rnd
|
|
||||||
|
|
||||||
// Commit additional memory up to new bytes.
|
|
||||||
err := unix.Mprotect(m.buf[com:new], unix.PROT_READ|unix.PROT_WRITE)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
m.buf = m.buf[:new] // Update committed memory.
|
|
||||||
}
|
|
||||||
// Limit returned capacity because bytes beyond
|
|
||||||
// len(m.buf) have not yet been committed.
|
|
||||||
return m.buf[:size:len(m.buf)]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mmappedMemory) Free() {
|
|
||||||
err := unix.Munmap(m.buf[:cap(m.buf)])
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
m.buf = nil
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package alloc // import "github.com/ncruces/go-sqlite3/internal/alloc"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/experimental"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMemory(cap, max uint64) experimental.LinearMemory {
|
|
||||||
// Round up to the page size.
|
|
||||||
rnd := uint64(windows.Getpagesize() - 1)
|
|
||||||
res := (max + rnd) &^ rnd
|
|
||||||
|
|
||||||
if res > math.MaxInt {
|
|
||||||
// This ensures uintptr(res) overflows to a large value,
|
|
||||||
// and windows.VirtualAlloc returns an error.
|
|
||||||
res = math.MaxUint64
|
|
||||||
}
|
|
||||||
|
|
||||||
com := res
|
|
||||||
kind := windows.MEM_COMMIT
|
|
||||||
if cap < max { // Commit memory only if cap=max.
|
|
||||||
com = 0
|
|
||||||
kind = windows.MEM_RESERVE
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserve res bytes of address space, to ensure we won't need to move it.
|
|
||||||
r, err := windows.VirtualAlloc(0, uintptr(res), uint32(kind), windows.PAGE_READWRITE)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
buf := unsafe.Slice((*byte)(unsafe.Pointer(r)), int(max))
|
|
||||||
mem := virtualMemory{addr: r, buf: buf[:com:res]}
|
|
||||||
return &mem
|
|
||||||
}
|
|
||||||
|
|
||||||
// The slice covers the entire mmapped memory:
|
|
||||||
// - len(buf) is the already committed memory,
|
|
||||||
// - cap(buf) is the reserved address space.
|
|
||||||
type virtualMemory struct {
|
|
||||||
buf []byte
|
|
||||||
addr uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *virtualMemory) Reallocate(size uint64) []byte {
|
|
||||||
com := uint64(len(m.buf))
|
|
||||||
res := uint64(cap(m.buf))
|
|
||||||
if com < size && size <= res {
|
|
||||||
// Grow geometrically, round up to the page size.
|
|
||||||
rnd := uint64(windows.Getpagesize() - 1)
|
|
||||||
new := com + com>>3
|
|
||||||
new = min(max(size, new), res)
|
|
||||||
new = (new + rnd) &^ rnd
|
|
||||||
|
|
||||||
// Commit additional memory up to new bytes.
|
|
||||||
_, err := windows.VirtualAlloc(m.addr, uintptr(new), windows.MEM_COMMIT, windows.PAGE_READWRITE)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
m.buf = m.buf[:new] // Update committed memory.
|
|
||||||
}
|
|
||||||
// Limit returned capacity because bytes beyond
|
|
||||||
// len(m.buf) have not yet been committed.
|
|
||||||
return m.buf[:size:len(m.buf)]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *virtualMemory) Free() {
|
|
||||||
err := windows.VirtualFree(m.addr, 0, windows.MEM_RELEASE)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
m.addr = 0
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
// internal/bootstrap/plugin.go
|
|
||||||
package bootstrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/cmd/flags"
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitPlugins 初始化插件管理器
|
|
||||||
func InitPlugins() {
|
|
||||||
// 2. 创建并初始化 Manager
|
|
||||||
// "data" 目录应从配置中获取
|
|
||||||
manager, err := plugin.NewManager(context.Background(), flags.DataDir)
|
|
||||||
if err != nil {
|
|
||||||
// 在启动时,如果插件系统失败,应该 panic
|
|
||||||
panic(fmt.Sprintf("Failed to initialize plugin manager: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.PluginManager = manager
|
|
||||||
}
|
|
||||||
+1
-1
@@ -12,7 +12,7 @@ var db *gorm.DB
|
|||||||
|
|
||||||
func Init(d *gorm.DB) {
|
func Init(d *gorm.DB) {
|
||||||
db = d
|
db = d
|
||||||
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem), new(model.SSHPublicKey), new(model.SharingDB), new(model.Plugin))
|
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem), new(model.SSHPublicKey), new(model.SharingDB))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed migrate database: %s", err.Error())
|
log.Fatalf("failed migrate database: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreatePlugin 在数据库中插入一条新的插件记录
|
|
||||||
// 如果记录已存在,则会更新它 (Upsert)
|
|
||||||
func CreatePlugin(ctx context.Context, plugin *model.Plugin) error {
|
|
||||||
return db.WithContext(ctx).Save(plugin).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPluginByID 从数据库中根据 ID 查询单个插件
|
|
||||||
func GetPluginByID(ctx context.Context, id string) (*model.Plugin, error) {
|
|
||||||
var plugin model.Plugin
|
|
||||||
err := db.WithContext(ctx).First(&plugin, "id = ?", id).Error
|
|
||||||
if err != nil {
|
|
||||||
if err == gorm.ErrRecordNotFound {
|
|
||||||
return nil, nil // 返回 nil, nil 表示未找到
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &plugin, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllPlugins 从数据库中获取所有已安装的插件
|
|
||||||
func GetAllPlugins(ctx context.Context) ([]*model.Plugin, error) {
|
|
||||||
var plugins []*model.Plugin
|
|
||||||
err := db.WithContext(ctx).Find(&plugins).Error
|
|
||||||
return plugins, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeletePluginByID 从数据库中根据 ID 删除一个插件
|
|
||||||
func DeletePluginByID(ctx context.Context, id string) error {
|
|
||||||
return db.WithContext(ctx).Delete(&model.Plugin{}, "id = ?", id).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatePluginStatus 更新指定插件的状态和消息
|
|
||||||
func UpdatePluginStatus(ctx context.Context, pluginID string, status model.PluginStatus, message string) error {
|
|
||||||
return db.WithContext(ctx).Model(&model.Plugin{}).Where("id = ?", pluginID).Updates(map[string]interface{}{
|
|
||||||
"status": status,
|
|
||||||
"message": message,
|
|
||||||
}).Error
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user