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

     1  package caches
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
     7  	rangeutils "github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
     8  	"github.com/iwind/TeaGo/types"
     9  	"io"
    10  	"os"
    11  )
    12  
    13  type FileReader struct {
    14  	fp *fsutils.File
    15  
    16  	openFile      *OpenFile
    17  	openFileCache *OpenFileCache
    18  
    19  	meta   []byte
    20  	header []byte
    21  
    22  	expiresAt    int64
    23  	status       int
    24  	headerOffset int64
    25  	headerSize   int
    26  	bodySize     int64
    27  	bodyOffset   int64
    28  
    29  	isClosed bool
    30  }
    31  
    32  func NewFileReader(fp *fsutils.File) *FileReader {
    33  	return &FileReader{fp: fp}
    34  }
    35  
    36  func (this *FileReader) Init() error {
    37  	return this.InitAutoDiscard(true)
    38  }
    39  
    40  func (this *FileReader) InitAutoDiscard(autoDiscard bool) error {
    41  	if this.openFile != nil {
    42  		this.meta = this.openFile.meta
    43  		this.header = this.openFile.header
    44  	}
    45  
    46  	var isOk = false
    47  
    48  	if autoDiscard {
    49  		defer func() {
    50  			if !isOk {
    51  				_ = this.discard()
    52  			}
    53  		}()
    54  	}
    55  
    56  	var buf = this.meta
    57  	if len(buf) == 0 {
    58  		buf = make([]byte, SizeMeta)
    59  		ok, err := this.readToBuff(this.fp, buf)
    60  		if err != nil {
    61  			return err
    62  		}
    63  		if !ok {
    64  			return ErrNotFound
    65  		}
    66  		this.meta = buf
    67  	}
    68  
    69  	this.expiresAt = int64(binary.BigEndian.Uint32(buf[:SizeExpiresAt]))
    70  
    71  	var status = types.Int(string(buf[OffsetStatus : OffsetStatus+SizeStatus]))
    72  	if status < 100 || status > 999 {
    73  		return errors.New("invalid status")
    74  	}
    75  	this.status = status
    76  
    77  	// URL
    78  	var urlLength = binary.BigEndian.Uint32(buf[OffsetURLLength : OffsetURLLength+SizeURLLength])
    79  
    80  	// header
    81  	var headerSize = int(binary.BigEndian.Uint32(buf[OffsetHeaderLength : OffsetHeaderLength+SizeHeaderLength]))
    82  	if headerSize == 0 {
    83  		return nil
    84  	}
    85  	this.headerSize = headerSize
    86  	this.headerOffset = int64(SizeMeta) + int64(urlLength)
    87  
    88  	// body
    89  	this.bodyOffset = this.headerOffset + int64(headerSize)
    90  	var bodySize = int(binary.BigEndian.Uint64(buf[OffsetBodyLength : OffsetBodyLength+SizeBodyLength]))
    91  	if bodySize == 0 {
    92  		isOk = true
    93  		return nil
    94  	}
    95  	this.bodySize = int64(bodySize)
    96  
    97  	// read header
    98  	if this.openFileCache != nil && len(this.header) == 0 {
    99  		if headerSize > 0 && headerSize <= 512 {
   100  			this.header = make([]byte, headerSize)
   101  			_, err := this.fp.Seek(this.headerOffset, io.SeekStart)
   102  			if err != nil {
   103  				return err
   104  			}
   105  			_, err = this.readToBuff(this.fp, this.header)
   106  			if err != nil {
   107  				return err
   108  			}
   109  		}
   110  	}
   111  
   112  	isOk = true
   113  
   114  	return nil
   115  }
   116  
   117  func (this *FileReader) TypeName() string {
   118  	return "disk"
   119  }
   120  
   121  func (this *FileReader) ExpiresAt() int64 {
   122  	return this.expiresAt
   123  }
   124  
   125  func (this *FileReader) Status() int {
   126  	return this.status
   127  }
   128  
   129  func (this *FileReader) LastModified() int64 {
   130  	stat, err := this.fp.Stat()
   131  	if err != nil {
   132  		return 0
   133  	}
   134  	return stat.ModTime().Unix()
   135  }
   136  
   137  func (this *FileReader) HeaderSize() int64 {
   138  	return int64(this.headerSize)
   139  }
   140  
   141  func (this *FileReader) BodySize() int64 {
   142  	return this.bodySize
   143  }
   144  
   145  func (this *FileReader) ReadHeader(buf []byte, callback ReaderFunc) error {
   146  	// 使用缓存
   147  	if len(this.header) > 0 && len(buf) >= len(this.header) {
   148  		copy(buf, this.header)
   149  		_, err := callback(len(this.header))
   150  		if err != nil {
   151  			return err
   152  		}
   153  
   154  		// 移动到Body位置
   155  		_, err = this.fp.Seek(this.bodyOffset, io.SeekStart)
   156  		if err != nil {
   157  			return err
   158  		}
   159  		return nil
   160  	}
   161  
   162  	var isOk = false
   163  
   164  	defer func() {
   165  		if !isOk {
   166  			_ = this.discard()
   167  		}
   168  	}()
   169  
   170  	_, err := this.fp.Seek(this.headerOffset, io.SeekStart)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	var headerSize = this.headerSize
   176  
   177  	for {
   178  		n, err := this.fp.Read(buf)
   179  		if n > 0 {
   180  			if n < headerSize {
   181  				goNext, e := callback(n)
   182  				if e != nil {
   183  					isOk = true
   184  					return e
   185  				}
   186  				if !goNext {
   187  					break
   188  				}
   189  				headerSize -= n
   190  			} else {
   191  				_, e := callback(headerSize)
   192  				if e != nil {
   193  					isOk = true
   194  					return e
   195  				}
   196  				break
   197  			}
   198  		}
   199  		if err != nil {
   200  			if err != io.EOF {
   201  				return err
   202  			}
   203  			break
   204  		}
   205  	}
   206  
   207  	isOk = true
   208  
   209  	// 移动到Body位置
   210  	_, err = this.fp.Seek(this.bodyOffset, io.SeekStart)
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	return nil
   216  }
   217  
   218  func (this *FileReader) ReadBody(buf []byte, callback ReaderFunc) error {
   219  	if this.bodySize == 0 {
   220  		return nil
   221  	}
   222  
   223  	var isOk = false
   224  
   225  	defer func() {
   226  		if !isOk {
   227  			_ = this.discard()
   228  		}
   229  	}()
   230  
   231  	var offset = this.bodyOffset
   232  
   233  	// 开始读Body部分
   234  	_, err := this.fp.Seek(offset, io.SeekStart)
   235  	if err != nil {
   236  		return err
   237  	}
   238  
   239  	for {
   240  		n, err := this.fp.Read(buf)
   241  		if n > 0 {
   242  			goNext, e := callback(n)
   243  			if e != nil {
   244  				isOk = true
   245  				return e
   246  			}
   247  			if !goNext {
   248  				break
   249  			}
   250  		}
   251  		if err != nil {
   252  			if err != io.EOF {
   253  				return err
   254  			}
   255  			break
   256  		}
   257  	}
   258  
   259  	isOk = true
   260  
   261  	return nil
   262  }
   263  
   264  func (this *FileReader) Read(buf []byte) (n int, err error) {
   265  	if this.bodySize == 0 {
   266  		n = 0
   267  		err = io.EOF
   268  		return
   269  	}
   270  
   271  	n, err = this.fp.Read(buf)
   272  	if err != nil && err != io.EOF {
   273  		_ = this.discard()
   274  	}
   275  
   276  	return
   277  }
   278  
   279  func (this *FileReader) ReadBodyRange(buf []byte, start int64, end int64, callback ReaderFunc) error {
   280  	var isOk = false
   281  
   282  	defer func() {
   283  		if !isOk {
   284  			_ = this.discard()
   285  		}
   286  	}()
   287  
   288  	var offset = start
   289  	if start < 0 {
   290  		offset = this.bodyOffset + this.bodySize + end
   291  		end = this.bodyOffset + this.bodySize - 1
   292  	} else if end < 0 {
   293  		offset = this.bodyOffset + start
   294  		end = this.bodyOffset + this.bodySize - 1
   295  	} else {
   296  		offset = this.bodyOffset + start
   297  		end = this.bodyOffset + end
   298  	}
   299  	if offset < 0 || end < 0 || offset > end {
   300  		isOk = true
   301  		return ErrInvalidRange
   302  	}
   303  	_, err := this.fp.Seek(offset, io.SeekStart)
   304  	if err != nil {
   305  		return err
   306  	}
   307  
   308  	for {
   309  		var n int
   310  		n, err = this.fp.Read(buf)
   311  		if n > 0 {
   312  			var n2 = int(end-offset) + 1
   313  			if n2 <= n {
   314  				_, e := callback(n2)
   315  				if e != nil {
   316  					isOk = true
   317  					return e
   318  				}
   319  				break
   320  			} else {
   321  				goNext, e := callback(n)
   322  				if e != nil {
   323  					isOk = true
   324  					return e
   325  				}
   326  				if !goNext {
   327  					break
   328  				}
   329  			}
   330  
   331  			offset += int64(n)
   332  			if offset > end {
   333  				break
   334  			}
   335  		}
   336  		if err != nil {
   337  			if err != io.EOF {
   338  				return err
   339  			}
   340  			break
   341  		}
   342  	}
   343  
   344  	isOk = true
   345  
   346  	return nil
   347  }
   348  
   349  // ContainsRange 是否包含某些区间内容
   350  func (this *FileReader) ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool) {
   351  	return r, true
   352  }
   353  
   354  // FP 原始的文件句柄
   355  func (this *FileReader) FP() *os.File {
   356  	return this.fp.Raw()
   357  }
   358  
   359  func (this *FileReader) Close() error {
   360  	if this.isClosed {
   361  		return nil
   362  	}
   363  	this.isClosed = true
   364  
   365  	if this.openFileCache != nil {
   366  		if this.openFile != nil {
   367  			this.openFileCache.Put(this.fp.Name(), this.openFile)
   368  		} else {
   369  			var cacheMeta = make([]byte, len(this.meta))
   370  			copy(cacheMeta, this.meta)
   371  			this.openFileCache.Put(this.fp.Name(), NewOpenFile(this.fp.Raw(), cacheMeta, this.header, this.LastModified(), this.bodySize))
   372  		}
   373  		return nil
   374  	}
   375  
   376  	return this.fp.Close()
   377  }
   378  
   379  func (this *FileReader) readToBuff(fp *fsutils.File, buf []byte) (ok bool, err error) {
   380  	n, err := fp.Read(buf)
   381  	if err != nil {
   382  		return false, err
   383  	}
   384  	ok = n == len(buf)
   385  	return
   386  }
   387  
   388  func (this *FileReader) discard() error {
   389  	_ = this.fp.Close()
   390  	this.isClosed = true
   391  
   392  	// close open file cache
   393  	if this.openFileCache != nil {
   394  		this.openFileCache.Close(this.fp.Name())
   395  	}
   396  
   397  	// remove file
   398  	return fsutils.Remove(this.fp.Name())
   399  }