github.com/TeaOSLab/EdgeNode@v1.3.8/internal/caches/writer_file.go (about)

     1  package caches
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
     7  	"github.com/iwind/TeaGo/types"
     8  	"io"
     9  	"strings"
    10  	"sync"
    11  )
    12  
    13  type FileWriter struct {
    14  	storage   StorageInterface
    15  	rawWriter *fsutils.File
    16  	key       string
    17  
    18  	metaHeaderSize int
    19  	headerSize     int64
    20  
    21  	metaBodySize int64 // 写入前的内容长度
    22  	bodySize     int64
    23  
    24  	expiredAt int64
    25  	maxSize   int64
    26  	endFunc   func()
    27  	once      sync.Once
    28  
    29  	modifiedBytes int
    30  }
    31  
    32  func NewFileWriter(storage StorageInterface, rawWriter *fsutils.File, key string, expiredAt int64, metaHeaderSize int, metaBodySize int64, maxSize int64, endFunc func()) *FileWriter {
    33  	return &FileWriter{
    34  		storage:        storage,
    35  		key:            key,
    36  		rawWriter:      rawWriter,
    37  		expiredAt:      expiredAt,
    38  		maxSize:        maxSize,
    39  		endFunc:        endFunc,
    40  		metaHeaderSize: metaHeaderSize,
    41  		metaBodySize:   metaBodySize,
    42  	}
    43  }
    44  
    45  // WriteHeader 写入数据
    46  func (this *FileWriter) WriteHeader(data []byte) (n int, err error) {
    47  	n, err = this.rawWriter.Write(data)
    48  	this.headerSize += int64(n)
    49  	if err != nil {
    50  		_ = this.Discard()
    51  	}
    52  	return
    53  }
    54  
    55  // WriteHeaderLength 写入Header长度数据
    56  func (this *FileWriter) WriteHeaderLength(headerLength int) error {
    57  	if this.metaHeaderSize > 0 && this.metaHeaderSize == headerLength {
    58  		return nil
    59  	}
    60  	var bytes4 = make([]byte, 4)
    61  	binary.BigEndian.PutUint32(bytes4, uint32(headerLength))
    62  	_, err := this.rawWriter.Seek(SizeExpiresAt+SizeStatus+SizeURLLength, io.SeekStart)
    63  	if err != nil {
    64  		_ = this.Discard()
    65  		return err
    66  	}
    67  	_, err = this.rawWriter.Write(bytes4)
    68  	if err != nil {
    69  		_ = this.Discard()
    70  		return err
    71  	}
    72  	return nil
    73  }
    74  
    75  // Write 写入数据
    76  func (this *FileWriter) Write(data []byte) (n int, err error) {
    77  	// split LARGE data
    78  	var l = len(data)
    79  	if l > (2 << 20) {
    80  		var offset = 0
    81  		const bufferSize = 64 << 10
    82  		for {
    83  			var end = offset + bufferSize
    84  			if end > l {
    85  				end = l
    86  			}
    87  			n1, err1 := this.write(data[offset:end])
    88  			n += n1
    89  			if err1 != nil {
    90  				return n, err1
    91  			}
    92  			if end >= l {
    93  				return n, nil
    94  			}
    95  			offset = end
    96  		}
    97  	}
    98  
    99  	// write NORMAL size data
   100  	return this.write(data)
   101  }
   102  
   103  // WriteAt 在指定位置写入数据
   104  func (this *FileWriter) WriteAt(offset int64, data []byte) error {
   105  	_ = data
   106  	_ = offset
   107  	return errors.New("not supported")
   108  }
   109  
   110  // WriteBodyLength 写入Body长度数据
   111  func (this *FileWriter) WriteBodyLength(bodyLength int64) error {
   112  	if this.metaBodySize >= 0 && bodyLength == this.metaBodySize {
   113  		return nil
   114  	}
   115  	var bytes8 = make([]byte, 8)
   116  	binary.BigEndian.PutUint64(bytes8, uint64(bodyLength))
   117  	_, err := this.rawWriter.Seek(SizeExpiresAt+SizeStatus+SizeURLLength+SizeHeaderLength, io.SeekStart)
   118  	if err != nil {
   119  		_ = this.Discard()
   120  		return err
   121  	}
   122  	_, err = this.rawWriter.Write(bytes8)
   123  	if err != nil {
   124  		_ = this.Discard()
   125  		return err
   126  	}
   127  	return nil
   128  }
   129  
   130  // Close 关闭
   131  func (this *FileWriter) Close() error {
   132  	defer this.once.Do(func() {
   133  		this.endFunc()
   134  	})
   135  
   136  	var path = this.rawWriter.Name()
   137  
   138  	// check content length
   139  	if this.metaBodySize > 0 && this.bodySize != this.metaBodySize {
   140  		_ = this.rawWriter.Close()
   141  		_ = fsutils.Remove(path)
   142  		return ErrUnexpectedContentLength
   143  	}
   144  
   145  	err := this.WriteHeaderLength(types.Int(this.headerSize))
   146  	if err != nil {
   147  		_ = this.rawWriter.Close()
   148  		_ = fsutils.Remove(path)
   149  		return err
   150  	}
   151  	err = this.WriteBodyLength(this.bodySize)
   152  	if err != nil {
   153  		_ = this.rawWriter.Close()
   154  		_ = fsutils.Remove(path)
   155  		return err
   156  	}
   157  
   158  	err = this.rawWriter.Close()
   159  	if err != nil {
   160  		_ = fsutils.Remove(path)
   161  	} else if strings.HasSuffix(path, FileTmpSuffix) {
   162  		err = fsutils.Rename(path, strings.Replace(path, FileTmpSuffix, "", 1))
   163  		if err != nil {
   164  			_ = fsutils.Remove(path)
   165  		}
   166  	}
   167  
   168  	return err
   169  }
   170  
   171  // Discard 丢弃
   172  func (this *FileWriter) Discard() error {
   173  	defer this.once.Do(func() {
   174  		this.endFunc()
   175  	})
   176  
   177  	_ = this.rawWriter.Close()
   178  
   179  	err := fsutils.Remove(this.rawWriter.Name())
   180  	return err
   181  }
   182  
   183  func (this *FileWriter) HeaderSize() int64 {
   184  	return this.headerSize
   185  }
   186  
   187  func (this *FileWriter) BodySize() int64 {
   188  	return this.bodySize
   189  }
   190  
   191  func (this *FileWriter) ExpiredAt() int64 {
   192  	return this.expiredAt
   193  }
   194  
   195  func (this *FileWriter) Key() string {
   196  	return this.key
   197  }
   198  
   199  // ItemType 获取内容类型
   200  func (this *FileWriter) ItemType() ItemType {
   201  	return ItemTypeFile
   202  }
   203  
   204  func (this *FileWriter) write(data []byte) (n int, err error) {
   205  	n, err = this.rawWriter.Write(data)
   206  	this.bodySize += int64(n)
   207  
   208  	if this.maxSize > 0 && this.bodySize > this.maxSize {
   209  		err = ErrEntityTooLarge
   210  
   211  		if this.storage != nil {
   212  			this.storage.IgnoreKey(this.key, this.maxSize)
   213  		}
   214  	}
   215  
   216  	if err != nil {
   217  		_ = this.Discard()
   218  	}
   219  
   220  	return
   221  }