Files
EdgeNode/internal/caches/reader_file.go

411 lines
7.3 KiB
Go
Raw Normal View History

2021-01-13 12:02:50 +08:00
package caches
import (
"encoding/binary"
"errors"
2024-04-29 22:01:55 +08:00
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
rangeutils "github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
2021-01-13 12:02:50 +08:00
"github.com/iwind/TeaGo/types"
"io"
"os"
)
type FileReader struct {
fp *os.File
2022-01-12 21:09:00 +08:00
openFile *OpenFile
openFileCache *OpenFileCache
meta []byte
header []byte
expiresAt int64
2021-01-13 12:02:50 +08:00
status int
headerOffset int64
headerSize int
bodySize int64
bodyOffset int64
isClosed bool
2021-01-13 12:02:50 +08:00
}
func NewFileReader(fp *os.File) *FileReader {
return &FileReader{fp: fp}
}
func (this *FileReader) Init() error {
return this.InitAutoDiscard(true)
}
func (this *FileReader) InitAutoDiscard(autoDiscard bool) error {
if this.openFile != nil {
this.meta = this.openFile.meta
this.header = this.openFile.header
}
2022-11-08 11:03:37 +08:00
var isOk = false
2021-01-13 12:02:50 +08:00
if autoDiscard {
defer func() {
if !isOk {
_ = this.discard()
}
}()
}
2021-01-13 12:02:50 +08:00
2022-01-12 21:09:00 +08:00
var buf = this.meta
if len(buf) == 0 {
buf = make([]byte, SizeMeta)
ok, err := this.readToBuff(this.fp, buf)
if err != nil {
return err
}
if !ok {
return ErrNotFound
}
this.meta = buf
2021-01-13 12:02:50 +08:00
}
2021-08-21 21:44:34 +08:00
this.expiresAt = int64(binary.BigEndian.Uint32(buf[:SizeExpiresAt]))
2022-11-08 11:03:37 +08:00
var status = types.Int(string(buf[OffsetStatus : OffsetStatus+SizeStatus]))
2021-01-13 12:02:50 +08:00
if status < 100 || status > 999 {
return errors.New("invalid status")
}
this.status = status
// URL
2022-11-08 11:03:37 +08:00
var urlLength = binary.BigEndian.Uint32(buf[OffsetURLLength : OffsetURLLength+SizeURLLength])
2021-01-13 12:02:50 +08:00
// header
2022-11-08 11:03:37 +08:00
var headerSize = int(binary.BigEndian.Uint32(buf[OffsetHeaderLength : OffsetHeaderLength+SizeHeaderLength]))
2021-01-13 12:02:50 +08:00
if headerSize == 0 {
return nil
}
this.headerSize = headerSize
this.headerOffset = int64(SizeMeta) + int64(urlLength)
// body
this.bodyOffset = this.headerOffset + int64(headerSize)
2022-11-08 11:03:37 +08:00
var bodySize = int(binary.BigEndian.Uint64(buf[OffsetBodyLength : OffsetBodyLength+SizeBodyLength]))
2021-01-13 12:02:50 +08:00
if bodySize == 0 {
isOk = true
2021-01-13 12:02:50 +08:00
return nil
}
this.bodySize = int64(bodySize)
// read header
if this.openFileCache != nil && len(this.header) == 0 {
if headerSize > 0 && headerSize <= 512 {
this.header = make([]byte, headerSize)
_, err := this.fp.Seek(this.headerOffset, io.SeekStart)
if err != nil {
return err
}
_, err = this.readToBuff(this.fp, this.header)
if err != nil {
return err
}
}
}
2021-01-13 12:02:50 +08:00
isOk = true
return nil
}
func (this *FileReader) TypeName() string {
return "disk"
}
func (this *FileReader) ExpiresAt() int64 {
return this.expiresAt
}
2021-01-13 12:02:50 +08:00
func (this *FileReader) Status() int {
return this.status
}
2021-06-14 11:46:39 +08:00
func (this *FileReader) LastModified() int64 {
stat, err := this.fp.Stat()
if err != nil {
return 0
}
return stat.ModTime().Unix()
}
2021-01-13 12:02:50 +08:00
func (this *FileReader) HeaderSize() int64 {
return int64(this.headerSize)
}
func (this *FileReader) BodySize() int64 {
return this.bodySize
}
func (this *FileReader) ReadHeader(buf []byte, callback ReaderFunc) error {
// 使用缓存
if len(this.header) > 0 && len(buf) >= len(this.header) {
copy(buf, this.header)
_, err := callback(len(this.header))
if err != nil {
return err
}
// 移动到Body位置
_, err = this.fp.Seek(this.bodyOffset, io.SeekStart)
if err != nil {
return err
}
return nil
}
2022-11-08 11:03:37 +08:00
var isOk = false
2021-01-13 12:02:50 +08:00
defer func() {
if !isOk {
_ = this.discard()
}
}()
_, err := this.fp.Seek(this.headerOffset, io.SeekStart)
if err != nil {
return err
}
2022-11-08 11:03:37 +08:00
var headerSize = this.headerSize
2021-01-13 16:11:28 +08:00
2021-01-13 12:02:50 +08:00
for {
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Ack()
2021-01-13 12:02:50 +08:00
n, err := this.fp.Read(buf)
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Release()
2021-01-13 12:02:50 +08:00
if n > 0 {
2021-01-13 16:11:28 +08:00
if n < headerSize {
2021-01-13 12:02:50 +08:00
goNext, e := callback(n)
if e != nil {
isOk = true
return e
}
if !goNext {
break
}
2021-01-13 16:11:28 +08:00
headerSize -= n
2021-01-13 12:02:50 +08:00
} else {
2021-01-13 16:11:28 +08:00
_, e := callback(headerSize)
2021-01-13 12:02:50 +08:00
if e != nil {
isOk = true
return e
}
break
}
}
if err != nil {
if err != io.EOF {
return err
}
break
}
}
isOk = true
// 移动到Body位置
_, err = this.fp.Seek(this.bodyOffset, io.SeekStart)
if err != nil {
return err
}
2021-01-13 12:02:50 +08:00
return nil
}
func (this *FileReader) ReadBody(buf []byte, callback ReaderFunc) error {
2022-12-14 15:26:18 +08:00
if this.bodySize == 0 {
return nil
}
2022-11-08 11:03:37 +08:00
var isOk = false
2021-01-13 12:02:50 +08:00
defer func() {
if !isOk {
_ = this.discard()
}
}()
var offset = this.bodyOffset
2021-01-13 16:11:28 +08:00
// 开始读Body部分
_, err := this.fp.Seek(offset, io.SeekStart)
2021-01-13 12:02:50 +08:00
if err != nil {
return err
}
for {
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Ack()
2021-01-13 12:02:50 +08:00
n, err := this.fp.Read(buf)
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Release()
2021-01-13 12:02:50 +08:00
if n > 0 {
goNext, e := callback(n)
if e != nil {
isOk = true
return e
}
if !goNext {
break
}
}
if err != nil {
if err != io.EOF {
return err
}
break
}
}
isOk = true
return nil
}
func (this *FileReader) Read(buf []byte) (n int, err error) {
2022-12-14 15:26:18 +08:00
if this.bodySize == 0 {
n = 0
err = io.EOF
return
}
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Ack()
n, err = this.fp.Read(buf)
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Release()
if err != nil && err != io.EOF {
_ = this.discard()
}
2022-11-08 11:03:37 +08:00
return
}
2021-01-13 12:02:50 +08:00
func (this *FileReader) ReadBodyRange(buf []byte, start int64, end int64, callback ReaderFunc) error {
2022-11-08 11:03:37 +08:00
var isOk = false
2021-01-13 12:02:50 +08:00
defer func() {
if !isOk {
_ = this.discard()
}
}()
2022-11-08 11:03:37 +08:00
var offset = start
2021-01-13 12:02:50 +08:00
if start < 0 {
offset = this.bodyOffset + this.bodySize + end
end = this.bodyOffset + this.bodySize - 1
} else if end < 0 {
offset = this.bodyOffset + start
end = this.bodyOffset + this.bodySize - 1
} else {
offset = this.bodyOffset + start
end = this.bodyOffset + end
}
if offset < 0 || end < 0 || offset > end {
isOk = true
return ErrInvalidRange
}
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Ack()
2021-01-13 12:02:50 +08:00
_, err := this.fp.Seek(offset, io.SeekStart)
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Release()
2021-01-13 12:02:50 +08:00
if err != nil {
return err
}
for {
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Ack()
2021-01-13 12:02:50 +08:00
n, err := this.fp.Read(buf)
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Release()
2021-01-13 12:02:50 +08:00
if n > 0 {
2022-11-08 11:03:37 +08:00
var n2 = int(end-offset) + 1
2021-01-13 12:02:50 +08:00
if n2 <= n {
_, e := callback(n2)
if e != nil {
isOk = true
return e
}
break
} else {
goNext, e := callback(n)
if e != nil {
isOk = true
return e
}
if !goNext {
break
}
}
offset += int64(n)
if offset > end {
break
}
}
if err != nil {
if err != io.EOF {
return err
}
break
}
}
isOk = true
return nil
}
// ContainsRange 是否包含某些区间内容
2022-03-04 22:42:03 +08:00
func (this *FileReader) ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool) {
return r, true
}
2022-04-04 18:25:54 +08:00
// FP 原始的文件句柄
func (this *FileReader) FP() *os.File {
return this.fp
}
2021-01-13 12:02:50 +08:00
func (this *FileReader) Close() error {
2022-11-08 11:03:37 +08:00
if this.isClosed {
return nil
}
this.isClosed = true
2022-11-08 11:03:37 +08:00
if this.openFileCache != nil {
2022-01-12 21:09:00 +08:00
if this.openFile != nil {
this.openFileCache.Put(this.fp.Name(), this.openFile)
} else {
2022-04-14 09:36:02 +08:00
var cacheMeta = make([]byte, len(this.meta))
copy(cacheMeta, this.meta)
2023-10-11 21:51:05 +08:00
this.openFileCache.Put(this.fp.Name(), NewOpenFile(this.fp, cacheMeta, this.header, this.LastModified(), this.bodySize))
2022-01-12 21:09:00 +08:00
}
return nil
}
2022-11-08 11:03:37 +08:00
2021-01-13 12:02:50 +08:00
return this.fp.Close()
}
func (this *FileReader) readToBuff(fp *os.File, buf []byte) (ok bool, err error) {
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Ack()
2021-01-13 12:02:50 +08:00
n, err := fp.Read(buf)
2024-04-29 22:01:55 +08:00
fsutils.ReaderLimiter.Release()
2021-01-13 12:02:50 +08:00
if err != nil {
return false, err
}
ok = n == len(buf)
return
}
func (this *FileReader) discard() error {
_ = this.fp.Close()
this.isClosed = true
// close open file cache
if this.openFileCache != nil {
this.openFileCache.Close(this.fp.Name())
}
// remove file
2021-01-13 12:02:50 +08:00
return os.Remove(this.fp.Name())
}