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 }