1
0
mirror of https://github.com/makew0rld/amfora.git synced 2024-10-01 23:25:56 -04:00
amfora/cache/cache.go
makeworld 543d15abfc 🔀 Refactor to use tab struct
Squashed commit of the following:

commit 72f36afc9e
Author: makeworld <colecmac@protonmail.com>
Date:   Tue Jul 7 16:15:45 2020 -0400

    🚧 Scroll is applied correctly when navigating around

commit 4b8982723f
Author: makeworld <colecmac@protonmail.com>
Date:   Tue Jul 7 15:34:45 2020 -0400

    🚧 Fix bottomBar code

    Make sure it always resets to a selected link if one was selected before

commit be09ffcf91
Author: makeworld <colecmac@protonmail.com>
Date:   Mon Jul 6 20:30:54 2020 -0400

    🚧 Switch to using tab pointers instead of ints

    Almost finished overall work.

commit ef8ab3da39
Author: makeworld <colecmac@protonmail.com>
Date:   Mon Jul 6 12:10:50 2020 -0400

    🚧 Fixed some bugs, major ones remain

commit d3d47a344d
Author: makeworld <colecmac@protonmail.com>
Date:   Sat Jul 4 20:58:46 2020 -0400

    🚧 Everything uses tab struct, no compile errors, untested

commit 44bf54c12f
Author: makeworld <colecmac@protonmail.com>
Date:   Sat Jul 4 13:24:49 2020 -0400

    🚧 Initial work on tab struct
2020-07-07 21:13:45 -04:00

121 lines
2.9 KiB
Go

// Package cache provides an interface for a cache of strings, aka text/gemini pages.
// It is fully thread safe.
package cache
import (
"strings"
"sync"
"github.com/makeworld-the-better-one/amfora/structs"
)
var pages = make(map[string]*structs.Page) // The actual cache
var urls = make([]string, 0) // Duplicate of the keys in the `pages` map, but in order of being added
var maxPages = 0 // Max allowed number of pages in cache
var maxSize = 0 // Max allowed cache size in bytes
var lock = sync.RWMutex{}
// SetMaxPages sets the max number of pages the cache can hold.
// A value <= 0 means infinite pages.
func SetMaxPages(max int) {
maxPages = max
}
// SetMaxSize sets the max size the cache can be, in bytes.
// A value <= 0 means infinite size.
func SetMaxSize(max int) {
maxSize = max
}
func removeIndex(s []string, i int) []string {
s[len(s)-1], s[i] = s[i], s[len(s)-1]
return s[:len(s)-1]
}
func removeUrl(url string) {
for i := range urls {
if urls[i] == url {
urls = removeIndex(urls, i)
return
}
}
}
// Add adds a page to the cache, removing earlier pages as needed
// to keep the cache inside its limits.
//
// If your page is larger than the max cache size, the provided page
// will silently not be added to the cache.
func Add(p *structs.Page) {
if p.Url == "" || strings.HasPrefix(p.Url, "about:") {
// Just in case, these pages shouldn't be cached
return
}
if p.Size() > maxSize && maxSize > 0 {
// This page can never be added
return
}
// Remove earlier pages to make room for this one
// There should only ever be 1 page to remove at most,
// but this handles more just in case.
for NumPages() >= maxPages && maxPages > 0 {
Remove(urls[0])
}
// Do the same but for cache size
for Size()+p.Size() > maxSize && maxSize > 0 {
Remove(urls[0])
}
lock.Lock()
defer lock.Unlock()
pages[p.Url] = p
// Remove the URL if it was already there, then add it to the end
removeUrl(p.Url)
urls = append(urls, p.Url)
}
// Remove will remove a page from the cache.
// Even if the page doesn't exist there will be no error.
func Remove(url string) {
lock.Lock()
defer lock.Unlock()
delete(pages, url)
removeUrl(url)
}
// Clear removes all pages from the cache.
func Clear() {
lock.Lock()
defer lock.Unlock()
pages = make(map[string]*structs.Page)
urls = make([]string, 0)
}
// Size returns the approx. current size of the cache in bytes.
func Size() int {
lock.RLock()
defer lock.RUnlock()
n := 0
for _, page := range pages {
n += page.Size()
}
return n
}
func NumPages() int {
lock.RLock()
defer lock.RUnlock()
return len(pages)
}
// Get returns the page struct, and a bool indicating if the page was in the cache or not.
// An empty page struct is returned if the page isn't in the cache.
func Get(url string) (*structs.Page, bool) {
lock.RLock()
defer lock.RUnlock()
p, ok := pages[url]
return p, ok
}