2020-10-05 16:55:14 +08:00
|
|
|
package caches
|
|
|
|
|
|
|
|
|
|
import (
|
2021-01-13 12:02:50 +08:00
|
|
|
"encoding/binary"
|
2022-02-21 17:33:58 +08:00
|
|
|
"errors"
|
2021-01-13 12:02:50 +08:00
|
|
|
"io"
|
|
|
|
|
"strings"
|
2021-12-21 00:27:32 +08:00
|
|
|
"sync"
|
2024-07-27 15:42:50 +08:00
|
|
|
|
|
|
|
|
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
|
|
|
|
"github.com/iwind/TeaGo/types"
|
2020-10-05 16:55:14 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type FileWriter struct {
|
2022-11-19 17:23:45 +08:00
|
|
|
storage StorageInterface
|
2024-05-01 15:53:49 +08:00
|
|
|
rawWriter *fsutils.File
|
2022-11-19 17:23:45 +08:00
|
|
|
key string
|
|
|
|
|
|
|
|
|
|
metaHeaderSize int
|
|
|
|
|
headerSize int64
|
|
|
|
|
|
|
|
|
|
metaBodySize int64 // 写入前的内容长度
|
|
|
|
|
bodySize int64
|
|
|
|
|
|
|
|
|
|
expiredAt int64
|
|
|
|
|
maxSize int64
|
|
|
|
|
endFunc func()
|
|
|
|
|
once sync.Once
|
2024-05-01 15:53:49 +08:00
|
|
|
|
|
|
|
|
modifiedBytes int
|
2020-10-05 16:55:14 +08:00
|
|
|
}
|
|
|
|
|
|
2024-05-01 15:53:49 +08:00
|
|
|
func NewFileWriter(storage StorageInterface, rawWriter *fsutils.File, key string, expiredAt int64, metaHeaderSize int, metaBodySize int64, maxSize int64, endFunc func()) *FileWriter {
|
2020-10-05 16:55:14 +08:00
|
|
|
return &FileWriter{
|
2022-11-19 17:23:45 +08:00
|
|
|
storage: storage,
|
|
|
|
|
key: key,
|
|
|
|
|
rawWriter: rawWriter,
|
|
|
|
|
expiredAt: expiredAt,
|
|
|
|
|
maxSize: maxSize,
|
|
|
|
|
endFunc: endFunc,
|
|
|
|
|
metaHeaderSize: metaHeaderSize,
|
|
|
|
|
metaBodySize: metaBodySize,
|
2020-10-05 16:55:14 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// WriteHeader 写入数据
|
2021-01-13 12:02:50 +08:00
|
|
|
func (this *FileWriter) WriteHeader(data []byte) (n int, err error) {
|
|
|
|
|
n, err = this.rawWriter.Write(data)
|
|
|
|
|
this.headerSize += int64(n)
|
|
|
|
|
if err != nil {
|
|
|
|
|
_ = this.Discard()
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// WriteHeaderLength 写入Header长度数据
|
2021-01-13 12:02:50 +08:00
|
|
|
func (this *FileWriter) WriteHeaderLength(headerLength int) error {
|
2022-11-19 17:23:45 +08:00
|
|
|
if this.metaHeaderSize > 0 && this.metaHeaderSize == headerLength {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
var bytes4 = make([]byte, 4)
|
2021-01-13 12:02:50 +08:00
|
|
|
binary.BigEndian.PutUint32(bytes4, uint32(headerLength))
|
|
|
|
|
_, err := this.rawWriter.Seek(SizeExpiresAt+SizeStatus+SizeURLLength, io.SeekStart)
|
|
|
|
|
if err != nil {
|
|
|
|
|
_ = this.Discard()
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
_, err = this.rawWriter.Write(bytes4)
|
|
|
|
|
if err != nil {
|
|
|
|
|
_ = this.Discard()
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// Write 写入数据
|
2020-10-05 16:55:14 +08:00
|
|
|
func (this *FileWriter) Write(data []byte) (n int, err error) {
|
2023-07-30 09:00:51 +08:00
|
|
|
// split LARGE data
|
|
|
|
|
var l = len(data)
|
|
|
|
|
if l > (2 << 20) {
|
|
|
|
|
var offset = 0
|
2024-05-01 15:53:49 +08:00
|
|
|
const bufferSize = 64 << 10
|
2023-07-30 09:00:51 +08:00
|
|
|
for {
|
|
|
|
|
var end = offset + bufferSize
|
|
|
|
|
if end > l {
|
|
|
|
|
end = l
|
|
|
|
|
}
|
|
|
|
|
n1, err1 := this.write(data[offset:end])
|
|
|
|
|
n += n1
|
|
|
|
|
if err1 != nil {
|
|
|
|
|
return n, err1
|
|
|
|
|
}
|
|
|
|
|
if end >= l {
|
|
|
|
|
return n, nil
|
|
|
|
|
}
|
|
|
|
|
offset = end
|
2022-03-06 17:18:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-30 09:00:51 +08:00
|
|
|
// write NORMAL size data
|
|
|
|
|
return this.write(data)
|
2020-10-05 16:55:14 +08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:33:58 +08:00
|
|
|
// WriteAt 在指定位置写入数据
|
2022-03-03 19:36:28 +08:00
|
|
|
func (this *FileWriter) WriteAt(offset int64, data []byte) error {
|
2022-02-21 17:33:58 +08:00
|
|
|
_ = data
|
|
|
|
|
_ = offset
|
|
|
|
|
return errors.New("not supported")
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// WriteBodyLength 写入Body长度数据
|
2021-01-13 12:02:50 +08:00
|
|
|
func (this *FileWriter) WriteBodyLength(bodyLength int64) error {
|
2022-11-19 17:23:45 +08:00
|
|
|
if this.metaBodySize >= 0 && bodyLength == this.metaBodySize {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
var bytes8 = make([]byte, 8)
|
2021-01-13 12:02:50 +08:00
|
|
|
binary.BigEndian.PutUint64(bytes8, uint64(bodyLength))
|
|
|
|
|
_, err := this.rawWriter.Seek(SizeExpiresAt+SizeStatus+SizeURLLength+SizeHeaderLength, io.SeekStart)
|
|
|
|
|
if err != nil {
|
|
|
|
|
_ = this.Discard()
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
_, err = this.rawWriter.Write(bytes8)
|
|
|
|
|
if err != nil {
|
|
|
|
|
_ = this.Discard()
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// Close 关闭
|
2020-10-05 16:55:14 +08:00
|
|
|
func (this *FileWriter) Close() error {
|
2021-12-21 00:27:32 +08:00
|
|
|
defer this.once.Do(func() {
|
|
|
|
|
this.endFunc()
|
|
|
|
|
})
|
|
|
|
|
|
2022-11-19 17:23:45 +08:00
|
|
|
var path = this.rawWriter.Name()
|
2021-06-06 23:42:11 +08:00
|
|
|
|
2024-04-05 11:45:18 +08:00
|
|
|
// check content length
|
|
|
|
|
if this.metaBodySize > 0 && this.bodySize != this.metaBodySize {
|
|
|
|
|
_ = this.rawWriter.Close()
|
2024-04-29 22:36:26 +08:00
|
|
|
_ = fsutils.Remove(path)
|
2024-04-05 11:45:18 +08:00
|
|
|
return ErrUnexpectedContentLength
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 12:02:50 +08:00
|
|
|
err := this.WriteHeaderLength(types.Int(this.headerSize))
|
2020-10-05 16:55:14 +08:00
|
|
|
if err != nil {
|
2021-12-21 00:27:32 +08:00
|
|
|
_ = this.rawWriter.Close()
|
2024-04-29 22:36:26 +08:00
|
|
|
_ = fsutils.Remove(path)
|
2021-01-13 12:02:50 +08:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
err = this.WriteBodyLength(this.bodySize)
|
|
|
|
|
if err != nil {
|
2021-12-21 00:27:32 +08:00
|
|
|
_ = this.rawWriter.Close()
|
2024-04-29 22:36:26 +08:00
|
|
|
_ = fsutils.Remove(path)
|
2021-01-13 12:02:50 +08:00
|
|
|
return err
|
2020-10-05 16:55:14 +08:00
|
|
|
}
|
|
|
|
|
|
2021-01-13 12:02:50 +08:00
|
|
|
err = this.rawWriter.Close()
|
|
|
|
|
if err != nil {
|
2024-04-29 22:36:26 +08:00
|
|
|
_ = fsutils.Remove(path)
|
2022-04-20 18:23:26 +08:00
|
|
|
} else if strings.HasSuffix(path, FileTmpSuffix) {
|
2024-04-29 22:36:26 +08:00
|
|
|
err = fsutils.Rename(path, strings.Replace(path, FileTmpSuffix, "", 1))
|
2021-01-13 12:02:50 +08:00
|
|
|
if err != nil {
|
2024-04-29 22:36:26 +08:00
|
|
|
_ = fsutils.Remove(path)
|
2021-01-13 12:02:50 +08:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-05 16:55:14 +08:00
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// Discard 丢弃
|
2020-10-05 16:55:14 +08:00
|
|
|
func (this *FileWriter) Discard() error {
|
2021-12-21 00:27:32 +08:00
|
|
|
defer this.once.Do(func() {
|
|
|
|
|
this.endFunc()
|
|
|
|
|
})
|
2021-06-06 23:42:11 +08:00
|
|
|
|
2021-01-13 12:02:50 +08:00
|
|
|
_ = this.rawWriter.Close()
|
|
|
|
|
|
2024-04-29 22:36:26 +08:00
|
|
|
err := fsutils.Remove(this.rawWriter.Name())
|
2020-10-05 16:55:14 +08:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 12:02:50 +08:00
|
|
|
func (this *FileWriter) HeaderSize() int64 {
|
|
|
|
|
return this.headerSize
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *FileWriter) BodySize() int64 {
|
|
|
|
|
return this.bodySize
|
2020-10-05 16:55:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *FileWriter) ExpiredAt() int64 {
|
|
|
|
|
return this.expiredAt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *FileWriter) Key() string {
|
|
|
|
|
return this.key
|
|
|
|
|
}
|
2021-03-02 19:43:05 +08:00
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
// ItemType 获取内容类型
|
2021-03-02 19:43:05 +08:00
|
|
|
func (this *FileWriter) ItemType() ItemType {
|
|
|
|
|
return ItemTypeFile
|
|
|
|
|
}
|
2023-07-30 09:00:51 +08:00
|
|
|
|
|
|
|
|
func (this *FileWriter) write(data []byte) (n int, err error) {
|
|
|
|
|
n, err = this.rawWriter.Write(data)
|
|
|
|
|
this.bodySize += int64(n)
|
|
|
|
|
|
|
|
|
|
if this.maxSize > 0 && this.bodySize > this.maxSize {
|
|
|
|
|
err = ErrEntityTooLarge
|
|
|
|
|
|
|
|
|
|
if this.storage != nil {
|
|
|
|
|
this.storage.IgnoreKey(this.key, this.maxSize)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
_ = this.Discard()
|
|
|
|
|
}
|
2024-05-01 15:53:49 +08:00
|
|
|
|
2023-07-30 09:00:51 +08:00
|
|
|
return
|
|
|
|
|
}
|