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 }