mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-09-20 04:36:09 +08:00
Compare commits
1 Commits
v4.1.1
...
renovate/g
Author | SHA1 | Date | |
---|---|---|---|
1a8307467b |
38
.github/workflows/sync_repo.yml
vendored
38
.github/workflows/sync_repo.yml
vendored
@ -1,38 +0,0 @@
|
|||||||
name: Sync to Gitee
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Sync GitHub to Gitee
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup SSH
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh
|
|
||||||
echo "${{ secrets.GITEE_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
|
||||||
chmod 600 ~/.ssh/id_rsa
|
|
||||||
ssh-keyscan gitee.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Create single commit and push
|
|
||||||
run: |
|
|
||||||
git config user.name "GitHub Actions"
|
|
||||||
git config user.email "actions@github.com"
|
|
||||||
|
|
||||||
# Create a new branch
|
|
||||||
git checkout --orphan new-main
|
|
||||||
git add .
|
|
||||||
git commit -m "Sync from GitHub: $(date)"
|
|
||||||
|
|
||||||
# Add Gitee remote and force push
|
|
||||||
git remote add gitee ${{ vars.GITEE_REPO_URL }}
|
|
||||||
git push --force gitee new-main:main
|
|
@ -6,9 +6,10 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- '5244:5244'
|
- '5244:5244'
|
||||||
- '5245:5245'
|
- '5245:5245'
|
||||||
user: '0:0'
|
|
||||||
environment:
|
environment:
|
||||||
|
- PUID=0
|
||||||
|
- PGID=0
|
||||||
- UMASK=022
|
- UMASK=022
|
||||||
- TZ=Asia/Shanghai
|
- TZ=UTC
|
||||||
container_name: openlist
|
container_name: openlist
|
||||||
image: 'openlistteam/openlist:latest'
|
image: 'openlistteam/openlist:latest'
|
||||||
|
@ -70,8 +70,6 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
|||||||
var reader *stream.SectionReader
|
var reader *stream.SectionReader
|
||||||
var rateLimitedRd io.Reader
|
var rateLimitedRd io.Reader
|
||||||
sliceMD5 := ""
|
sliceMD5 := ""
|
||||||
// 表单
|
|
||||||
b := bytes.NewBuffer(make([]byte, 0, 2048))
|
|
||||||
threadG.GoWithLifecycle(errgroup.Lifecycle{
|
threadG.GoWithLifecycle(errgroup.Lifecycle{
|
||||||
Before: func(ctx context.Context) error {
|
Before: func(ctx context.Context) error {
|
||||||
if reader == nil {
|
if reader == nil {
|
||||||
@ -86,6 +84,7 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
rateLimitedRd = driver.NewLimitedUploadStream(ctx, reader)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@ -93,8 +92,9 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
|||||||
// 重置分片reader位置,因为HashReader、上一次失败已经读取到分片EOF
|
// 重置分片reader位置,因为HashReader、上一次失败已经读取到分片EOF
|
||||||
reader.Seek(0, io.SeekStart)
|
reader.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
b.Reset()
|
// 创建表单数据
|
||||||
w := multipart.NewWriter(b)
|
var b bytes.Buffer
|
||||||
|
w := multipart.NewWriter(&b)
|
||||||
// 添加表单字段
|
// 添加表单字段
|
||||||
err = w.WriteField("preuploadID", createResp.Data.PreuploadID)
|
err = w.WriteField("preuploadID", createResp.Data.PreuploadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -109,20 +109,21 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// 写入文件内容
|
// 写入文件内容
|
||||||
_, err = w.CreateFormFile("slice", fmt.Sprintf("%s.part%d", file.GetName(), partNumber))
|
fw, err := w.CreateFormFile("slice", fmt.Sprintf("%s.part%d", file.GetName(), partNumber))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = utils.CopyWithBuffer(fw, rateLimitedRd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
headSize := b.Len()
|
|
||||||
err = w.Close()
|
err = w.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
head := bytes.NewReader(b.Bytes()[:headSize])
|
|
||||||
tail := bytes.NewReader(b.Bytes()[headSize:])
|
|
||||||
rateLimitedRd = driver.NewLimitedUploadStream(ctx, io.MultiReader(head, reader, tail))
|
|
||||||
// 创建请求并设置header
|
// 创建请求并设置header
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadDomain+"/upload/v2/file/slice", rateLimitedRd)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadDomain+"/upload/v2/file/slice", &b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ type Addition struct {
|
|||||||
ClientSecret string `json:"client_secret" required:"false" help:"Keep it empty if you don't have one"`
|
ClientSecret string `json:"client_secret" required:"false" help:"Keep it empty if you don't have one"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
RefreshToken string `json:"refresh_token" required:"true"`
|
RefreshToken string `json:"refresh_token" required:"true"`
|
||||||
RootNamespaceId string `json:"RootNamespaceId" required:"false"`
|
RootNamespaceId string
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = driver.Config{
|
var config = driver.Config{
|
||||||
|
@ -175,13 +175,6 @@ func (d *Dropbox) finishUploadSession(ctx context.Context, toPath string, offset
|
|||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/octet-stream")
|
req.Header.Set("Content-Type", "application/octet-stream")
|
||||||
req.Header.Set("Authorization", "Bearer "+d.AccessToken)
|
req.Header.Set("Authorization", "Bearer "+d.AccessToken)
|
||||||
if d.RootNamespaceId != "" {
|
|
||||||
apiPathRootJson, err := d.buildPathRootHeader()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.Header.Set("Dropbox-API-Path-Root", apiPathRootJson)
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadFinishArgs := UploadFinishArgs{
|
uploadFinishArgs := UploadFinishArgs{
|
||||||
Commit: struct {
|
Commit: struct {
|
||||||
@ -226,13 +219,6 @@ func (d *Dropbox) startUploadSession(ctx context.Context) (string, error) {
|
|||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/octet-stream")
|
req.Header.Set("Content-Type", "application/octet-stream")
|
||||||
req.Header.Set("Authorization", "Bearer "+d.AccessToken)
|
req.Header.Set("Authorization", "Bearer "+d.AccessToken)
|
||||||
if d.RootNamespaceId != "" {
|
|
||||||
apiPathRootJson, err := d.buildPathRootHeader()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
req.Header.Set("Dropbox-API-Path-Root", apiPathRootJson)
|
|
||||||
}
|
|
||||||
req.Header.Set("Dropbox-API-Arg", "{\"close\":false}")
|
req.Header.Set("Dropbox-API-Arg", "{\"close\":false}")
|
||||||
|
|
||||||
res, err := base.HttpClient.Do(req)
|
res, err := base.HttpClient.Do(req)
|
||||||
@ -247,11 +233,3 @@ func (d *Dropbox) startUploadSession(ctx context.Context) (string, error) {
|
|||||||
_ = res.Body.Close()
|
_ = res.Body.Close()
|
||||||
return sessionId, nil
|
return sessionId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dropbox) buildPathRootHeader() (string, error) {
|
|
||||||
return utils.Json.MarshalToString(map[string]interface{}{
|
|
||||||
".tag": "root",
|
|
||||||
"root": d.RootNamespaceId,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ func (d *Terabox) Remove(ctx context.Context, obj model.Obj) error {
|
|||||||
func (d *Terabox) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
|
func (d *Terabox) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
|
||||||
resp, err := base.RestyClient.R().
|
resp, err := base.RestyClient.R().
|
||||||
SetContext(ctx).
|
SetContext(ctx).
|
||||||
Get("https://" + d.url_domain_prefix + "-data.terabox.com/rest/2.0/pcs/file?method=locateupload")
|
Get("https://d.terabox.com/rest/2.0/pcs/file?method=locateupload")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,11 @@ umask ${UMASK}
|
|||||||
if [ "$1" = "version" ]; then
|
if [ "$1" = "version" ]; then
|
||||||
./openlist version
|
./openlist version
|
||||||
else
|
else
|
||||||
|
# Define the target directory path for openlist service
|
||||||
|
OPENLIST_DIR="/opt/service/start/openlist"
|
||||||
|
if [ ! -d "$OPENLIST_DIR" ]; then
|
||||||
|
cp -r /opt/service/stop/openlist "$OPENLIST_DIR" 2>/dev/null
|
||||||
|
fi
|
||||||
# Define the target directory path for aria2 service
|
# Define the target directory path for aria2 service
|
||||||
ARIA2_DIR="/opt/service/start/aria2"
|
ARIA2_DIR="/opt/service/start/aria2"
|
||||||
|
|
||||||
@ -14,12 +19,12 @@ else
|
|||||||
mkdir -p "$ARIA2_DIR"
|
mkdir -p "$ARIA2_DIR"
|
||||||
cp -r /opt/service/stop/aria2/* "$ARIA2_DIR" 2>/dev/null
|
cp -r /opt/service/stop/aria2/* "$ARIA2_DIR" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
runsvdir /opt/service/start &
|
|
||||||
else
|
else
|
||||||
# If aria2 should NOT run and target directory exists, remove it
|
# If aria2 should NOT run and target directory exists, remove it
|
||||||
if [ -d "$ARIA2_DIR" ]; then
|
if [ -d "$ARIA2_DIR" ]; then
|
||||||
rm -rf "$ARIA2_DIR"
|
rm -rf "$ARIA2_DIR"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
exec ./openlist server --no-prefix
|
|
||||||
|
exec runsvdir /opt/service/start
|
||||||
fi
|
fi
|
||||||
|
3
go.mod
3
go.mod
@ -70,7 +70,8 @@ require (
|
|||||||
golang.org/x/net v0.42.0
|
golang.org/x/net v0.42.0
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.30.0
|
||||||
golang.org/x/time v0.12.0
|
golang.org/x/time v0.12.0
|
||||||
google.golang.org/appengine v1.6.8
|
google.golang.org/appengine v1.6.7
|
||||||
|
google.golang.org/appengine/v2 v2.0.6
|
||||||
gopkg.in/ldap.v3 v3.1.0
|
gopkg.in/ldap.v3 v3.1.0
|
||||||
gorm.io/driver/mysql v1.5.7
|
gorm.io/driver/mysql v1.5.7
|
||||||
gorm.io/driver/postgres v1.5.9
|
gorm.io/driver/postgres v1.5.9
|
||||||
|
4
go.sum
4
go.sum
@ -892,8 +892,11 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||||
|
google.golang.org/appengine/v2 v2.0.6/go.mod h1:WoEXGoXNfa0mLvaH5sV3ZSGXwVmy8yf7Z1JKf3J3wLI=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
@ -920,6 +923,7 @@ google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
|||||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
|
||||||
|
@ -77,10 +77,6 @@ func InitConfig() {
|
|||||||
log.Fatalf("update config struct error: %+v", err)
|
log.Fatalf("update config struct error: %+v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !conf.Conf.Force {
|
|
||||||
confFromEnv()
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.Conf.MaxConcurrency > 0 {
|
if conf.Conf.MaxConcurrency > 0 {
|
||||||
net.DefaultConcurrencyLimit = &net.ConcurrencyLimit{Limit: conf.Conf.MaxConcurrency}
|
net.DefaultConcurrencyLimit = &net.ConcurrencyLimit{Limit: conf.Conf.MaxConcurrency}
|
||||||
}
|
}
|
||||||
@ -96,31 +92,25 @@ func InitConfig() {
|
|||||||
conf.MaxBufferLimit = conf.Conf.MaxBufferLimit * utils.MB
|
conf.MaxBufferLimit = conf.Conf.MaxBufferLimit * utils.MB
|
||||||
}
|
}
|
||||||
log.Infof("max buffer limit: %dMB", conf.MaxBufferLimit/utils.MB)
|
log.Infof("max buffer limit: %dMB", conf.MaxBufferLimit/utils.MB)
|
||||||
if conf.Conf.MmapThreshold > 0 {
|
if !conf.Conf.Force {
|
||||||
conf.MmapThreshold = conf.Conf.MmapThreshold * utils.MB
|
confFromEnv()
|
||||||
} else {
|
|
||||||
conf.MmapThreshold = 0
|
|
||||||
}
|
}
|
||||||
log.Infof("mmap threshold: %dMB", conf.Conf.MmapThreshold)
|
|
||||||
|
|
||||||
if len(conf.Conf.Log.Filter.Filters) == 0 {
|
if len(conf.Conf.Log.Filter.Filters) == 0 {
|
||||||
conf.Conf.Log.Filter.Enable = false
|
conf.Conf.Log.Filter.Enable = false
|
||||||
}
|
}
|
||||||
// convert abs path
|
// convert abs path
|
||||||
convertAbsPath := func(path *string) {
|
convertAbsPath := func(path *string) {
|
||||||
if *path != "" && !filepath.IsAbs(*path) {
|
if !filepath.IsAbs(*path) {
|
||||||
*path = filepath.Join(pwd, *path)
|
*path = filepath.Join(pwd, *path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
convertAbsPath(&conf.Conf.Database.DBFile)
|
|
||||||
convertAbsPath(&conf.Conf.Scheme.CertFile)
|
|
||||||
convertAbsPath(&conf.Conf.Scheme.KeyFile)
|
|
||||||
convertAbsPath(&conf.Conf.Scheme.UnixFile)
|
|
||||||
convertAbsPath(&conf.Conf.Log.Name)
|
|
||||||
convertAbsPath(&conf.Conf.TempDir)
|
convertAbsPath(&conf.Conf.TempDir)
|
||||||
convertAbsPath(&conf.Conf.BleveDir)
|
convertAbsPath(&conf.Conf.BleveDir)
|
||||||
|
convertAbsPath(&conf.Conf.Log.Name)
|
||||||
|
convertAbsPath(&conf.Conf.Database.DBFile)
|
||||||
|
if conf.Conf.DistDir != "" {
|
||||||
convertAbsPath(&conf.Conf.DistDir)
|
convertAbsPath(&conf.Conf.DistDir)
|
||||||
|
}
|
||||||
err := os.MkdirAll(conf.Conf.TempDir, 0o777)
|
err := os.MkdirAll(conf.Conf.TempDir, 0o777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("create temp dir error: %+v", err)
|
log.Fatalf("create temp dir error: %+v", err)
|
||||||
|
@ -120,7 +120,6 @@ type Config struct {
|
|||||||
Log LogConfig `json:"log" envPrefix:"LOG_"`
|
Log LogConfig `json:"log" envPrefix:"LOG_"`
|
||||||
DelayedStart int `json:"delayed_start" env:"DELAYED_START"`
|
DelayedStart int `json:"delayed_start" env:"DELAYED_START"`
|
||||||
MaxBufferLimit int `json:"max_buffer_limitMB" env:"MAX_BUFFER_LIMIT_MB"`
|
MaxBufferLimit int `json:"max_buffer_limitMB" env:"MAX_BUFFER_LIMIT_MB"`
|
||||||
MmapThreshold int `json:"mmap_thresholdMB" env:"MMAP_THRESHOLD_MB"`
|
|
||||||
MaxConnections int `json:"max_connections" env:"MAX_CONNECTIONS"`
|
MaxConnections int `json:"max_connections" env:"MAX_CONNECTIONS"`
|
||||||
MaxConcurrency int `json:"max_concurrency" env:"MAX_CONCURRENCY"`
|
MaxConcurrency int `json:"max_concurrency" env:"MAX_CONCURRENCY"`
|
||||||
TlsInsecureSkipVerify bool `json:"tls_insecure_skip_verify" env:"TLS_INSECURE_SKIP_VERIFY"`
|
TlsInsecureSkipVerify bool `json:"tls_insecure_skip_verify" env:"TLS_INSECURE_SKIP_VERIFY"`
|
||||||
@ -177,7 +176,6 @@ func DefaultConfig(dataDir string) *Config {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
MaxBufferLimit: -1,
|
MaxBufferLimit: -1,
|
||||||
MmapThreshold: 4,
|
|
||||||
MaxConnections: 0,
|
MaxConnections: 0,
|
||||||
MaxConcurrency: 64,
|
MaxConcurrency: 64,
|
||||||
TlsInsecureSkipVerify: true,
|
TlsInsecureSkipVerify: true,
|
||||||
|
@ -25,10 +25,7 @@ var PrivacyReg []*regexp.Regexp
|
|||||||
var (
|
var (
|
||||||
// StoragesLoaded loaded success if empty
|
// StoragesLoaded loaded success if empty
|
||||||
StoragesLoaded = false
|
StoragesLoaded = false
|
||||||
// 单个Buffer最大限制
|
|
||||||
MaxBufferLimit = 16 * 1024 * 1024
|
MaxBufferLimit = 16 * 1024 * 1024
|
||||||
// 超过该阈值的Buffer将使用 mmap 分配,可主动释放内存
|
|
||||||
MmapThreshold = 4 * 1024 * 1024
|
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
RawIndexHtml string
|
RawIndexHtml string
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -14,7 +15,6 @@ import (
|
|||||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||||
"github.com/rclone/rclone/lib/mmap"
|
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
@ -255,10 +255,7 @@ func (d *downloader) sendChunkTask(newConcurrency bool) error {
|
|||||||
finalSize += firstSize - minSize
|
finalSize += firstSize - minSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := buf.Reset(int(finalSize))
|
buf.Reset(int(finalSize))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ch := chunk{
|
ch := chunk{
|
||||||
start: d.pos,
|
start: d.pos,
|
||||||
size: finalSize,
|
size: finalSize,
|
||||||
@ -648,13 +645,11 @@ func (mr MultiReadCloser) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Buf struct {
|
type Buf struct {
|
||||||
|
buffer *bytes.Buffer
|
||||||
size int //expected size
|
size int //expected size
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
offR int
|
off int
|
||||||
offW int
|
|
||||||
rw sync.Mutex
|
rw sync.Mutex
|
||||||
buf []byte
|
|
||||||
mmap bool
|
|
||||||
|
|
||||||
readSignal chan struct{}
|
readSignal chan struct{}
|
||||||
readPending bool
|
readPending bool
|
||||||
@ -663,62 +658,54 @@ type Buf struct {
|
|||||||
// NewBuf is a buffer that can have 1 read & 1 write at the same time.
|
// NewBuf is a buffer that can have 1 read & 1 write at the same time.
|
||||||
// when read is faster write, immediately feed data to read after written
|
// when read is faster write, immediately feed data to read after written
|
||||||
func NewBuf(ctx context.Context, maxSize int) *Buf {
|
func NewBuf(ctx context.Context, maxSize int) *Buf {
|
||||||
br := &Buf{
|
return &Buf{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
buffer: bytes.NewBuffer(make([]byte, 0, maxSize)),
|
||||||
size: maxSize,
|
size: maxSize,
|
||||||
|
|
||||||
readSignal: make(chan struct{}, 1),
|
readSignal: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
if conf.MmapThreshold > 0 && maxSize >= conf.MmapThreshold {
|
|
||||||
m, err := mmap.Alloc(maxSize)
|
|
||||||
if err == nil {
|
|
||||||
br.buf = m
|
|
||||||
br.mmap = true
|
|
||||||
return br
|
|
||||||
}
|
|
||||||
}
|
|
||||||
br.buf = make([]byte, maxSize)
|
|
||||||
return br
|
|
||||||
}
|
}
|
||||||
|
func (br *Buf) Reset(size int) {
|
||||||
func (br *Buf) Reset(size int) error {
|
|
||||||
br.rw.Lock()
|
br.rw.Lock()
|
||||||
defer br.rw.Unlock()
|
defer br.rw.Unlock()
|
||||||
if br.buf == nil {
|
if br.buffer == nil {
|
||||||
return io.ErrClosedPipe
|
return
|
||||||
}
|
|
||||||
if size > cap(br.buf) {
|
|
||||||
return fmt.Errorf("reset size %d exceeds max size %d", size, cap(br.buf))
|
|
||||||
}
|
}
|
||||||
|
br.buffer.Reset()
|
||||||
br.size = size
|
br.size = size
|
||||||
br.offR = 0
|
br.off = 0
|
||||||
br.offW = 0
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *Buf) Read(p []byte) (int, error) {
|
func (br *Buf) Read(p []byte) (n int, err error) {
|
||||||
if err := br.ctx.Err(); err != nil {
|
if err := br.ctx.Err(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
if br.offR >= br.size {
|
if br.off >= br.size {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
br.rw.Lock()
|
br.rw.Lock()
|
||||||
if br.buf == nil {
|
if br.buffer != nil {
|
||||||
br.rw.Unlock()
|
n, err = br.buffer.Read(p)
|
||||||
return 0, io.ErrClosedPipe
|
} else {
|
||||||
|
err = io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
if br.offW < br.offR {
|
|
||||||
br.rw.Unlock()
|
br.rw.Unlock()
|
||||||
return 0, io.ErrUnexpectedEOF
|
return
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
br.off += n
|
||||||
|
br.rw.Unlock()
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
if br.offW == br.offR {
|
|
||||||
br.readPending = true
|
br.readPending = true
|
||||||
br.rw.Unlock()
|
br.rw.Unlock()
|
||||||
|
// n==0, err==io.EOF
|
||||||
select {
|
select {
|
||||||
case <-br.ctx.Done():
|
case <-br.ctx.Done():
|
||||||
return 0, br.ctx.Err()
|
return 0, br.ctx.Err()
|
||||||
@ -729,34 +716,18 @@ func (br *Buf) Read(p []byte) (int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n := copy(p, br.buf[br.offR:br.offW])
|
|
||||||
br.offR += n
|
|
||||||
br.rw.Unlock()
|
|
||||||
if n < len(p) && br.offR >= br.size {
|
|
||||||
return n, io.EOF
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *Buf) Write(p []byte) (int, error) {
|
func (br *Buf) Write(p []byte) (n int, err error) {
|
||||||
if err := br.ctx.Err(); err != nil {
|
if err := br.ctx.Err(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if len(p) == 0 {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
br.rw.Lock()
|
br.rw.Lock()
|
||||||
defer br.rw.Unlock()
|
defer br.rw.Unlock()
|
||||||
if br.buf == nil {
|
if br.buffer == nil {
|
||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
if br.offW >= br.size {
|
n, err = br.buffer.Write(p)
|
||||||
return 0, io.ErrShortWrite
|
|
||||||
}
|
|
||||||
n := copy(br.buf[br.offW:], p[:min(br.size-br.offW, len(p))])
|
|
||||||
br.offW += n
|
|
||||||
if br.readPending {
|
if br.readPending {
|
||||||
br.readPending = false
|
br.readPending = false
|
||||||
select {
|
select {
|
||||||
@ -764,21 +735,12 @@ func (br *Buf) Write(p []byte) (int, error) {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if n < len(p) {
|
return
|
||||||
return n, io.ErrShortWrite
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *Buf) Close() error {
|
func (br *Buf) Close() {
|
||||||
br.rw.Lock()
|
br.rw.Lock()
|
||||||
defer br.rw.Unlock()
|
defer br.rw.Unlock()
|
||||||
var err error
|
br.buffer = nil
|
||||||
if br.mmap {
|
|
||||||
err = mmap.Free(br.buf)
|
|
||||||
br.mmap = false
|
|
||||||
}
|
|
||||||
br.buf = nil
|
|
||||||
close(br.readSignal)
|
close(br.readSignal)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/OpenListTeam/OpenList/v4/pkg/buffer"
|
"github.com/OpenListTeam/OpenList/v4/pkg/buffer"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||||
"github.com/rclone/rclone/lib/mmap"
|
|
||||||
"go4.org/readerutil"
|
"go4.org/readerutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,12 +60,8 @@ func (f *FileStream) IsForceStreamUpload() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileStream) Close() error {
|
func (f *FileStream) Close() error {
|
||||||
if f.peekBuff != nil {
|
|
||||||
f.peekBuff.Reset()
|
|
||||||
f.peekBuff = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var err1, err2 error
|
var err1, err2 error
|
||||||
|
|
||||||
err1 = f.Closers.Close()
|
err1 = f.Closers.Close()
|
||||||
if errors.Is(err1, os.ErrClosed) {
|
if errors.Is(err1, os.ErrClosed) {
|
||||||
err1 = nil
|
err1 = nil
|
||||||
@ -79,6 +74,10 @@ func (f *FileStream) Close() error {
|
|||||||
f.tmpFile = nil
|
f.tmpFile = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if f.peekBuff != nil {
|
||||||
|
f.peekBuff.Reset()
|
||||||
|
f.peekBuff = nil
|
||||||
|
}
|
||||||
|
|
||||||
return errors.Join(err1, err2)
|
return errors.Join(err1, err2)
|
||||||
}
|
}
|
||||||
@ -195,19 +194,7 @@ func (f *FileStream) cache(maxCacheSize int64) (model.File, error) {
|
|||||||
f.oriReader = f.Reader
|
f.oriReader = f.Reader
|
||||||
}
|
}
|
||||||
bufSize := maxCacheSize - int64(f.peekBuff.Len())
|
bufSize := maxCacheSize - int64(f.peekBuff.Len())
|
||||||
var buf []byte
|
buf := make([]byte, bufSize)
|
||||||
if conf.MmapThreshold > 0 && bufSize >= int64(conf.MmapThreshold) {
|
|
||||||
m, err := mmap.Alloc(int(bufSize))
|
|
||||||
if err == nil {
|
|
||||||
f.Add(utils.CloseFunc(func() error {
|
|
||||||
return mmap.Free(m)
|
|
||||||
}))
|
|
||||||
buf = m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if buf == nil {
|
|
||||||
buf = make([]byte, bufSize)
|
|
||||||
}
|
|
||||||
n, err := io.ReadFull(f.oriReader, buf)
|
n, err := io.ReadFull(f.oriReader, buf)
|
||||||
if bufSize != int64(n) {
|
if bufSize != int64(n) {
|
||||||
return nil, fmt.Errorf("failed to read all data: (expect =%d, actual =%d) %w", bufSize, n, err)
|
return nil, fmt.Errorf("failed to read all data: (expect =%d, actual =%d) %w", bufSize, n, err)
|
||||||
|
@ -7,13 +7,11 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileStream_RangeRead(t *testing.T) {
|
func TestFileStream_RangeRead(t *testing.T) {
|
||||||
conf.MaxBufferLimit = 16 * 1024 * 1024
|
|
||||||
type args struct {
|
type args struct {
|
||||||
httpRange http_range.Range
|
httpRange http_range.Range
|
||||||
}
|
}
|
||||||
@ -73,7 +71,7 @@ func TestFileStream_RangeRead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
t.Run("after", func(t *testing.T) {
|
t.Run("after check", func(t *testing.T) {
|
||||||
if f.GetFile() == nil {
|
if f.GetFile() == nil {
|
||||||
t.Error("not cached")
|
t.Error("not cached")
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/net"
|
"github.com/OpenListTeam/OpenList/v4/internal/net"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/pool"
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||||
"github.com/rclone/rclone/lib/mmap"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -154,49 +153,26 @@ func CacheFullAndHash(stream model.FileStreamer, up *model.UpdateProgress, hashT
|
|||||||
type StreamSectionReader struct {
|
type StreamSectionReader struct {
|
||||||
file model.FileStreamer
|
file model.FileStreamer
|
||||||
off int64
|
off int64
|
||||||
bufPool *pool.Pool[[]byte]
|
bufPool *sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStreamSectionReader(file model.FileStreamer, maxBufferSize int, up *model.UpdateProgress) (*StreamSectionReader, error) {
|
func NewStreamSectionReader(file model.FileStreamer, maxBufferSize int, up *model.UpdateProgress) (*StreamSectionReader, error) {
|
||||||
ss := &StreamSectionReader{file: file}
|
ss := &StreamSectionReader{file: file}
|
||||||
if file.GetFile() != nil {
|
if file.GetFile() == nil {
|
||||||
return ss, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
maxBufferSize = min(maxBufferSize, int(file.GetSize()))
|
maxBufferSize = min(maxBufferSize, int(file.GetSize()))
|
||||||
if maxBufferSize > conf.MaxBufferLimit {
|
if maxBufferSize > conf.MaxBufferLimit {
|
||||||
_, err := file.CacheFullAndWriter(up, nil)
|
_, err := file.CacheFullAndWriter(up, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ss, nil
|
|
||||||
}
|
|
||||||
if conf.MmapThreshold > 0 && maxBufferSize >= conf.MmapThreshold {
|
|
||||||
ss.bufPool = &pool.Pool[[]byte]{
|
|
||||||
New: func() []byte {
|
|
||||||
buf, err := mmap.Alloc(maxBufferSize)
|
|
||||||
if err == nil {
|
|
||||||
file.Add(utils.CloseFunc(func() error {
|
|
||||||
return mmap.Free(buf)
|
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
buf = make([]byte, maxBufferSize)
|
ss.bufPool = &sync.Pool{
|
||||||
}
|
New: func() any {
|
||||||
return buf
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ss.bufPool = &pool.Pool[[]byte]{
|
|
||||||
New: func() []byte {
|
|
||||||
return make([]byte, maxBufferSize)
|
return make([]byte, maxBufferSize)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
file.Add(utils.CloseFunc(func() error {
|
|
||||||
ss.bufPool.Reset()
|
|
||||||
return nil
|
|
||||||
}))
|
|
||||||
return ss, nil
|
return ss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +184,7 @@ func (ss *StreamSectionReader) GetSectionReader(off, length int64) (*SectionRead
|
|||||||
if off != ss.off {
|
if off != ss.off {
|
||||||
return nil, fmt.Errorf("stream not cached: request offset %d != current offset %d", off, ss.off)
|
return nil, fmt.Errorf("stream not cached: request offset %d != current offset %d", off, ss.off)
|
||||||
}
|
}
|
||||||
tempBuf := ss.bufPool.Get()
|
tempBuf := ss.bufPool.Get().([]byte)
|
||||||
buf = tempBuf[:length]
|
buf = tempBuf[:length]
|
||||||
n, err := io.ReadFull(ss.file, buf)
|
n, err := io.ReadFull(ss.file, buf)
|
||||||
if int64(n) != length {
|
if int64(n) != length {
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package pool
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
type Pool[T any] struct {
|
|
||||||
New func() T
|
|
||||||
MaxCap int
|
|
||||||
|
|
||||||
cache []T
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pool[T]) Get() T {
|
|
||||||
p.mu.Lock()
|
|
||||||
defer p.mu.Unlock()
|
|
||||||
if len(p.cache) == 0 {
|
|
||||||
return p.New()
|
|
||||||
}
|
|
||||||
item := p.cache[len(p.cache)-1]
|
|
||||||
p.cache = p.cache[:len(p.cache)-1]
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pool[T]) Put(item T) {
|
|
||||||
p.mu.Lock()
|
|
||||||
defer p.mu.Unlock()
|
|
||||||
if p.MaxCap == 0 || len(p.cache) < int(p.MaxCap) {
|
|
||||||
p.cache = append(p.cache, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pool[T]) Reset() {
|
|
||||||
p.mu.Lock()
|
|
||||||
defer p.mu.Unlock()
|
|
||||||
clear(p.cache)
|
|
||||||
p.cache = nil
|
|
||||||
}
|
|
Reference in New Issue
Block a user