diff options
| author | Shulhan <ms@kilabit.info> | 2025-06-21 15:20:01 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2025-06-27 12:19:23 +0700 |
| commit | 1ca561ed0ecfa59b70a10191ac8e58cde90d126e (patch) | |
| tree | 80f0c65f7e9321ad92dfc1a53a444226cee4be3d /cache.go | |
| parent | 8bc8fce1bd80b5a25c452ac5a24b1a1e3f5a4feb (diff) | |
| download | jarink-1ca561ed0ecfa59b70a10191ac8e58cde90d126e.tar.xz | |
brokenlinks: implement caching for external URLs
Any succesful fetch on external URLs, will be recorded into jarink
cache file, located in user's home cache directory.
For example, in Linux it would be `$HOME/.cache/jarink/cache.json`.
This help improve the future rescanning on the same or different target
URL, minimizing network requests.
Diffstat (limited to 'cache.go')
| -rw-r--r-- | cache.go | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..12c7b74 --- /dev/null +++ b/cache.go @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2025 M. Shulhan <ms@kilabit.info> +// SPDX-License-Identifier: GPL-3.0-only + +package jarink + +import ( + "encoding/json" + "fmt" + "os" + "sync" + + "git.sr.ht/~shulhan/jarink/internal" +) + +// ScannedLink store information about the link. +type ScannedLink struct { + Url string `json:"url"` + Size int64 `json:"size"` + ResponseCode int `json:"response_code"` +} + +// Cache store external links that has been scanned, to minize +// request to the same URL in the future. +// The cache is stored as JSON file under user's cache directory, inside +// "jarink" directory. +// For example, in Linux it should be "$HOME/.cache/jarink/cache.json". +// See [os.UserCacheDir] for location specific to operating system. +type Cache struct { + ScannedLinks map[string]*ScannedLink `json:"scanned_links"` + file string + mtx sync.Mutex +} + +// LoadCache from local storage. +func LoadCache() (cache *Cache, err error) { + var logp = `LoadCache` + + cache = &Cache{ + ScannedLinks: map[string]*ScannedLink{}, + } + + cache.file, err = internal.CacheFile() + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + var cacheJson []byte + cacheJson, err = os.ReadFile(cache.file) + if err != nil { + if os.IsNotExist(err) { + return cache, nil + } + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + err = json.Unmarshal(cacheJson, &cache) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + return cache, nil +} + +// Get return the scanned link information by url. +func (cache *Cache) Get(url string) (scannedLink *ScannedLink) { + cache.mtx.Lock() + scannedLink = cache.ScannedLinks[url] + cache.mtx.Unlock() + return scannedLink +} + +// Save the cache into local storage. +func (cache *Cache) Save() (err error) { + var logp = `Save` + var cacheJson []byte + cacheJson, err = json.MarshalIndent(cache, ``, ` `) + if err != nil { + return fmt.Errorf(`%s: %w`, logp, err) + } + + cacheJson = append(cacheJson, '\n') + + err = os.WriteFile(cache.file, cacheJson, 0600) + if err != nil { + return fmt.Errorf(`%s: %w`, logp, err) + } + return nil +} + +func (cache *Cache) Set(url string, respCode int, size int64) { + cache.mtx.Lock() + defer cache.mtx.Unlock() + + var scannedLink = cache.ScannedLinks[url] + if scannedLink != nil { + return + } + scannedLink = &ScannedLink{ + Url: url, + Size: size, + ResponseCode: respCode, + } + cache.ScannedLinks[url] = scannedLink +} |
