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 | |
---|---|---|---|
18a4aa1a29 |
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:
|
||||
- '5244:5244'
|
||||
- '5245:5245'
|
||||
user: '0:0'
|
||||
environment:
|
||||
- PUID=0
|
||||
- PGID=0
|
||||
- UMASK=022
|
||||
- TZ=Asia/Shanghai
|
||||
- TZ=UTC
|
||||
container_name: openlist
|
||||
image: 'openlistteam/openlist:latest'
|
||||
|
@ -70,8 +70,6 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
||||
var reader *stream.SectionReader
|
||||
var rateLimitedRd io.Reader
|
||||
sliceMD5 := ""
|
||||
// 表单
|
||||
b := bytes.NewBuffer(make([]byte, 0, 2048))
|
||||
threadG.GoWithLifecycle(errgroup.Lifecycle{
|
||||
Before: func(ctx context.Context) error {
|
||||
if reader == nil {
|
||||
@ -86,6 +84,7 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rateLimitedRd = driver.NewLimitedUploadStream(ctx, reader)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@ -93,8 +92,9 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
||||
// 重置分片reader位置,因为HashReader、上一次失败已经读取到分片EOF
|
||||
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)
|
||||
if err != nil {
|
||||
@ -109,20 +109,21 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
headSize := b.Len()
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
head := bytes.NewReader(b.Bytes()[:headSize])
|
||||
tail := bytes.NewReader(b.Bytes()[headSize:])
|
||||
rateLimitedRd = driver.NewLimitedUploadStream(ctx, io.MultiReader(head, reader, tail))
|
||||
|
||||
// 创建请求并设置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 {
|
||||
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"`
|
||||
AccessToken string
|
||||
RefreshToken string `json:"refresh_token" required:"true"`
|
||||
RootNamespaceId string `json:"RootNamespaceId" required:"false"`
|
||||
RootNamespaceId string
|
||||
}
|
||||
|
||||
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("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{
|
||||
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("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}")
|
||||
|
||||
res, err := base.HttpClient.Do(req)
|
||||
@ -247,11 +233,3 @@ func (d *Dropbox) startUploadSession(ctx context.Context) (string, error) {
|
||||
_ = res.Body.Close()
|
||||
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 {
|
||||
resp, err := base.RestyClient.R().
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -5,6 +5,11 @@ umask ${UMASK}
|
||||
if [ "$1" = "version" ]; then
|
||||
./openlist version
|
||||
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
|
||||
ARIA2_DIR="/opt/service/start/aria2"
|
||||
|
||||
@ -14,12 +19,12 @@ else
|
||||
mkdir -p "$ARIA2_DIR"
|
||||
cp -r /opt/service/stop/aria2/* "$ARIA2_DIR" 2>/dev/null
|
||||
fi
|
||||
runsvdir /opt/service/start &
|
||||
else
|
||||
# If aria2 should NOT run and target directory exists, remove it
|
||||
if [ -d "$ARIA2_DIR" ]; then
|
||||
rm -rf "$ARIA2_DIR"
|
||||
fi
|
||||
fi
|
||||
exec ./openlist server --no-prefix
|
||||
|
||||
exec runsvdir /opt/service/start
|
||||
fi
|
||||
|
8
go.mod
8
go.mod
@ -73,7 +73,7 @@ require (
|
||||
google.golang.org/appengine v1.6.8
|
||||
gopkg.in/ldap.v3 v3.1.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/driver/postgres v1.5.9
|
||||
gorm.io/driver/postgres v1.6.0
|
||||
gorm.io/driver/sqlite v1.5.6
|
||||
gorm.io/gorm v1.25.11
|
||||
)
|
||||
@ -118,7 +118,7 @@ require (
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hekmon/cunits/v2 v2.1.0 // indirect
|
||||
github.com/ipfs/boxo v0.12.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/matoous/go-nanoid/v2 v2.1.0 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.27
|
||||
@ -188,8 +188,8 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/ipfs/go-cid v0.5.0
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
|
8
go.sum
8
go.sum
@ -392,10 +392,16 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
@ -948,6 +954,8 @@ gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
|
||||
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||
gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
|
||||
gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
|
@ -77,10 +77,6 @@ func InitConfig() {
|
||||
log.Fatalf("update config struct error: %+v", err)
|
||||
}
|
||||
}
|
||||
if !conf.Conf.Force {
|
||||
confFromEnv()
|
||||
}
|
||||
|
||||
if conf.Conf.MaxConcurrency > 0 {
|
||||
net.DefaultConcurrencyLimit = &net.ConcurrencyLimit{Limit: conf.Conf.MaxConcurrency}
|
||||
}
|
||||
@ -96,31 +92,25 @@ func InitConfig() {
|
||||
conf.MaxBufferLimit = conf.Conf.MaxBufferLimit * utils.MB
|
||||
}
|
||||
log.Infof("max buffer limit: %dMB", conf.MaxBufferLimit/utils.MB)
|
||||
if conf.Conf.MmapThreshold > 0 {
|
||||
conf.MmapThreshold = conf.Conf.MmapThreshold * utils.MB
|
||||
} else {
|
||||
conf.MmapThreshold = 0
|
||||
if !conf.Conf.Force {
|
||||
confFromEnv()
|
||||
}
|
||||
log.Infof("mmap threshold: %dMB", conf.Conf.MmapThreshold)
|
||||
|
||||
if len(conf.Conf.Log.Filter.Filters) == 0 {
|
||||
conf.Conf.Log.Filter.Enable = false
|
||||
}
|
||||
// convert abs path
|
||||
convertAbsPath := func(path *string) {
|
||||
if *path != "" && !filepath.IsAbs(*path) {
|
||||
if !filepath.IsAbs(*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.BleveDir)
|
||||
convertAbsPath(&conf.Conf.DistDir)
|
||||
|
||||
convertAbsPath(&conf.Conf.Log.Name)
|
||||
convertAbsPath(&conf.Conf.Database.DBFile)
|
||||
if conf.Conf.DistDir != "" {
|
||||
convertAbsPath(&conf.Conf.DistDir)
|
||||
}
|
||||
err := os.MkdirAll(conf.Conf.TempDir, 0o777)
|
||||
if err != nil {
|
||||
log.Fatalf("create temp dir error: %+v", err)
|
||||
|
@ -120,7 +120,6 @@ type Config struct {
|
||||
Log LogConfig `json:"log" envPrefix:"LOG_"`
|
||||
DelayedStart int `json:"delayed_start" env:"DELAYED_START"`
|
||||
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"`
|
||||
MaxConcurrency int `json:"max_concurrency" env:"MAX_CONCURRENCY"`
|
||||
TlsInsecureSkipVerify bool `json:"tls_insecure_skip_verify" env:"TLS_INSECURE_SKIP_VERIFY"`
|
||||
@ -177,7 +176,6 @@ func DefaultConfig(dataDir string) *Config {
|
||||
},
|
||||
},
|
||||
MaxBufferLimit: -1,
|
||||
MmapThreshold: 4,
|
||||
MaxConnections: 0,
|
||||
MaxConcurrency: 64,
|
||||
TlsInsecureSkipVerify: true,
|
||||
|
@ -25,10 +25,7 @@ var PrivacyReg []*regexp.Regexp
|
||||
var (
|
||||
// StoragesLoaded loaded success if empty
|
||||
StoragesLoaded = false
|
||||
// 单个Buffer最大限制
|
||||
MaxBufferLimit = 16 * 1024 * 1024
|
||||
// 超过该阈值的Buffer将使用 mmap 分配,可主动释放内存
|
||||
MmapThreshold = 4 * 1024 * 1024
|
||||
)
|
||||
var (
|
||||
RawIndexHtml string
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -14,7 +15,6 @@ import (
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||
"github.com/rclone/rclone/lib/mmap"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
@ -255,10 +255,7 @@ func (d *downloader) sendChunkTask(newConcurrency bool) error {
|
||||
finalSize += firstSize - minSize
|
||||
}
|
||||
}
|
||||
err := buf.Reset(int(finalSize))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Reset(int(finalSize))
|
||||
ch := chunk{
|
||||
start: d.pos,
|
||||
size: finalSize,
|
||||
@ -648,13 +645,11 @@ func (mr MultiReadCloser) Close() error {
|
||||
}
|
||||
|
||||
type Buf struct {
|
||||
size int //expected size
|
||||
ctx context.Context
|
||||
offR int
|
||||
offW int
|
||||
rw sync.Mutex
|
||||
buf []byte
|
||||
mmap bool
|
||||
buffer *bytes.Buffer
|
||||
size int //expected size
|
||||
ctx context.Context
|
||||
off int
|
||||
rw sync.Mutex
|
||||
|
||||
readSignal chan struct{}
|
||||
readPending bool
|
||||
@ -663,100 +658,76 @@ type Buf struct {
|
||||
// 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
|
||||
func NewBuf(ctx context.Context, maxSize int) *Buf {
|
||||
br := &Buf{
|
||||
ctx: ctx,
|
||||
size: maxSize,
|
||||
return &Buf{
|
||||
ctx: ctx,
|
||||
buffer: bytes.NewBuffer(make([]byte, 0, maxSize)),
|
||||
size: maxSize,
|
||||
|
||||
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) error {
|
||||
func (br *Buf) Reset(size int) {
|
||||
br.rw.Lock()
|
||||
defer br.rw.Unlock()
|
||||
if br.buf == nil {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
if size > cap(br.buf) {
|
||||
return fmt.Errorf("reset size %d exceeds max size %d", size, cap(br.buf))
|
||||
if br.buffer == nil {
|
||||
return
|
||||
}
|
||||
br.buffer.Reset()
|
||||
br.size = size
|
||||
br.offR = 0
|
||||
br.offW = 0
|
||||
return nil
|
||||
br.off = 0
|
||||
}
|
||||
|
||||
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 {
|
||||
return 0, err
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if br.offR >= br.size {
|
||||
if br.off >= br.size {
|
||||
return 0, io.EOF
|
||||
}
|
||||
for {
|
||||
br.rw.Lock()
|
||||
if br.buf == nil {
|
||||
br.rw.Unlock()
|
||||
return 0, io.ErrClosedPipe
|
||||
if br.buffer != nil {
|
||||
n, err = br.buffer.Read(p)
|
||||
} else {
|
||||
err = io.ErrClosedPipe
|
||||
}
|
||||
|
||||
if br.offW < br.offR {
|
||||
if err != nil && err != io.EOF {
|
||||
br.rw.Unlock()
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
return
|
||||
}
|
||||
if br.offW == br.offR {
|
||||
br.readPending = true
|
||||
if n > 0 {
|
||||
br.off += n
|
||||
br.rw.Unlock()
|
||||
select {
|
||||
case <-br.ctx.Done():
|
||||
return 0, br.ctx.Err()
|
||||
case _, ok := <-br.readSignal:
|
||||
if !ok {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
continue
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
n := copy(p, br.buf[br.offR:br.offW])
|
||||
br.offR += n
|
||||
br.readPending = true
|
||||
br.rw.Unlock()
|
||||
if n < len(p) && br.offR >= br.size {
|
||||
return n, io.EOF
|
||||
// n==0, err==io.EOF
|
||||
select {
|
||||
case <-br.ctx.Done():
|
||||
return 0, br.ctx.Err()
|
||||
case _, ok := <-br.readSignal:
|
||||
if !ok {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
continue
|
||||
}
|
||||
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 {
|
||||
return 0, err
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
br.rw.Lock()
|
||||
defer br.rw.Unlock()
|
||||
if br.buf == nil {
|
||||
if br.buffer == nil {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
if br.offW >= br.size {
|
||||
return 0, io.ErrShortWrite
|
||||
}
|
||||
n := copy(br.buf[br.offW:], p[:min(br.size-br.offW, len(p))])
|
||||
br.offW += n
|
||||
n, err = br.buffer.Write(p)
|
||||
if br.readPending {
|
||||
br.readPending = false
|
||||
select {
|
||||
@ -764,21 +735,12 @@ func (br *Buf) Write(p []byte) (int, error) {
|
||||
default:
|
||||
}
|
||||
}
|
||||
if n < len(p) {
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
return n, nil
|
||||
return
|
||||
}
|
||||
|
||||
func (br *Buf) Close() error {
|
||||
func (br *Buf) Close() {
|
||||
br.rw.Lock()
|
||||
defer br.rw.Unlock()
|
||||
var err error
|
||||
if br.mmap {
|
||||
err = mmap.Free(br.buf)
|
||||
br.mmap = false
|
||||
}
|
||||
br.buf = nil
|
||||
br.buffer = nil
|
||||
close(br.readSignal)
|
||||
return err
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/buffer"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||
"github.com/rclone/rclone/lib/mmap"
|
||||
"go4.org/readerutil"
|
||||
)
|
||||
|
||||
@ -61,12 +60,8 @@ func (f *FileStream) IsForceStreamUpload() bool {
|
||||
}
|
||||
|
||||
func (f *FileStream) Close() error {
|
||||
if f.peekBuff != nil {
|
||||
f.peekBuff.Reset()
|
||||
f.peekBuff = nil
|
||||
}
|
||||
|
||||
var err1, err2 error
|
||||
|
||||
err1 = f.Closers.Close()
|
||||
if errors.Is(err1, os.ErrClosed) {
|
||||
err1 = nil
|
||||
@ -79,6 +74,10 @@ func (f *FileStream) Close() error {
|
||||
f.tmpFile = nil
|
||||
}
|
||||
}
|
||||
if f.peekBuff != nil {
|
||||
f.peekBuff.Reset()
|
||||
f.peekBuff = nil
|
||||
}
|
||||
|
||||
return errors.Join(err1, err2)
|
||||
}
|
||||
@ -195,19 +194,7 @@ func (f *FileStream) cache(maxCacheSize int64) (model.File, error) {
|
||||
f.oriReader = f.Reader
|
||||
}
|
||||
bufSize := maxCacheSize - int64(f.peekBuff.Len())
|
||||
var buf []byte
|
||||
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)
|
||||
}
|
||||
buf := make([]byte, bufSize)
|
||||
n, err := io.ReadFull(f.oriReader, buf)
|
||||
if bufSize != int64(n) {
|
||||
return nil, fmt.Errorf("failed to read all data: (expect =%d, actual =%d) %w", bufSize, n, err)
|
||||
|
@ -7,13 +7,11 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||
)
|
||||
|
||||
func TestFileStream_RangeRead(t *testing.T) {
|
||||
conf.MaxBufferLimit = 16 * 1024 * 1024
|
||||
type args struct {
|
||||
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 {
|
||||
t.Error("not cached")
|
||||
}
|
||||
|
@ -8,14 +8,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/net"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/pool"
|
||||
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
||||
"github.com/rclone/rclone/lib/mmap"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -154,49 +153,26 @@ func CacheFullAndHash(stream model.FileStreamer, up *model.UpdateProgress, hashT
|
||||
type StreamSectionReader struct {
|
||||
file model.FileStreamer
|
||||
off int64
|
||||
bufPool *pool.Pool[[]byte]
|
||||
bufPool *sync.Pool
|
||||
}
|
||||
|
||||
func NewStreamSectionReader(file model.FileStreamer, maxBufferSize int, up *model.UpdateProgress) (*StreamSectionReader, error) {
|
||||
ss := &StreamSectionReader{file: file}
|
||||
if file.GetFile() != nil {
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
maxBufferSize = min(maxBufferSize, int(file.GetSize()))
|
||||
if maxBufferSize > conf.MaxBufferLimit {
|
||||
_, err := file.CacheFullAndWriter(up, nil)
|
||||
if err != nil {
|
||||
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 {
|
||||
buf = make([]byte, maxBufferSize)
|
||||
}
|
||||
return buf
|
||||
},
|
||||
}
|
||||
} else {
|
||||
ss.bufPool = &pool.Pool[[]byte]{
|
||||
New: func() []byte {
|
||||
return make([]byte, maxBufferSize)
|
||||
},
|
||||
if file.GetFile() == nil {
|
||||
maxBufferSize = min(maxBufferSize, int(file.GetSize()))
|
||||
if maxBufferSize > conf.MaxBufferLimit {
|
||||
_, err := file.CacheFullAndWriter(up, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ss.bufPool = &sync.Pool{
|
||||
New: func() any {
|
||||
return make([]byte, maxBufferSize)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.Add(utils.CloseFunc(func() error {
|
||||
ss.bufPool.Reset()
|
||||
return nil
|
||||
}))
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
@ -208,7 +184,7 @@ func (ss *StreamSectionReader) GetSectionReader(off, length int64) (*SectionRead
|
||||
if 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]
|
||||
n, err := io.ReadFull(ss.file, buf)
|
||||
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