(key *Key)
| 90 | } |
| 91 | |
| 92 | func (f *fileSystemCache) Get(key *Key) (*CachedData, error) { |
| 93 | fp := key.filePath(f.dir) |
| 94 | file, err := os.Open(fp) |
| 95 | if err != nil { |
| 96 | return nil, ErrMissing |
| 97 | } |
| 98 | |
| 99 | // the file will be closed once it's read as an io.ReaderCloser |
| 100 | // This ReaderCloser is stored in the returned CachedData |
| 101 | fi, err := file.Stat() |
| 102 | if err != nil { |
| 103 | return nil, fmt.Errorf("cache %q: cannot stat %q: %w", f.Name(), fp, err) |
| 104 | } |
| 105 | mt := fi.ModTime() |
| 106 | age := time.Since(mt) |
| 107 | if age > f.expire { |
| 108 | // check if file exceeded expiration time + grace time |
| 109 | if age > f.expire+f.grace { |
| 110 | file.Close() |
| 111 | return nil, ErrMissing |
| 112 | } |
| 113 | // Serve expired file in the hope it will be substituted |
| 114 | // with the fresh file during deadline. |
| 115 | } |
| 116 | |
| 117 | if err != nil { |
| 118 | file.Close() |
| 119 | return nil, fmt.Errorf("failed to read file content from %q: %w", f.Name(), err) |
| 120 | } |
| 121 | |
| 122 | metadata, err := decodeHeader(file) |
| 123 | if err != nil { |
| 124 | return nil, err |
| 125 | } |
| 126 | |
| 127 | value := &CachedData{ |
| 128 | ContentMetadata: *metadata, |
| 129 | Data: file, |
| 130 | Ttl: f.expire - age, |
| 131 | } |
| 132 | |
| 133 | return value, nil |
| 134 | } |
| 135 | |
| 136 | // decodeHeader decodes header from raw byte stream. Data is encoded as follows: |
| 137 | // length(contentType)|contentType|length(contentEncoding)|contentEncoding|length(contentLength)|contentLength|cachedData |
nothing calls this directly
no test coverage detected