icons: implement positive/negative cache TTLs

Signed-off-by: Steven Noonan <steven@uplinklabs.net>
This commit is contained in:
Steven Noonan 2018-12-18 13:33:32 -08:00
parent 848cd1dbec
commit a55c048a62
No known key found for this signature in database
GPG Key ID: 7EACB44BA7B30DB9
1 changed files with 55 additions and 1 deletions

View File

@ -1,5 +1,7 @@
use std::io::prelude::*; use std::io::prelude::*;
use std::fs::{create_dir_all, File}; use std::fs::{symlink_metadata, create_dir_all, remove_file, File};
use std::time::SystemTime;
use std::error::Error;
use rocket::Route; use rocket::Route;
use rocket::response::Content; use rocket::response::Content;
@ -44,12 +46,23 @@ fn get_icon (domain: &str) -> Vec<u8> {
}, },
Err(e) => { Err(e) => {
error!("Error downloading icon: {:?}", e); error!("Error downloading icon: {:?}", e);
mark_negcache(&path);
get_fallback_icon() get_fallback_icon()
} }
} }
} }
fn get_cached_icon(path: &str) -> Option<Vec<u8>> { fn get_cached_icon(path: &str) -> Option<Vec<u8>> {
// Check for expiration of negatively cached copy
if icon_is_negcached(path) {
return Some(get_fallback_icon());
}
// Check for expiration of successfully cached copy
if icon_is_expired(path) {
return None
}
// Try to read the cached icon, and return it if it exists // Try to read the cached icon, and return it if it exists
if let Ok(mut f) = File::open(path) { if let Ok(mut f) = File::open(path) {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
@ -62,6 +75,47 @@ fn get_cached_icon(path: &str) -> Option<Vec<u8>> {
None None
} }
fn file_is_expired(path: &str, ttl: u64) -> Result<bool, Box<Error>> {
let meta = symlink_metadata(path)?;
let modified = meta.modified()?;
let age = SystemTime::now().duration_since(modified)?;
Ok(ttl > 0 && ttl <= age.as_secs())
}
fn icon_is_negcached(path: &str) -> bool {
let miss_indicator = path.to_owned() + ".miss";
let expired = file_is_expired(&miss_indicator, CONFIG.icon_cache_negttl);
match expired {
// No longer negatively cached, drop the marker
Ok(true) => {
match remove_file(&miss_indicator) {
Ok(_) => {},
Err(e) => {
error!("Could not remove negative cache indicator for icon {:?}: {:?}", path, e);
}
}
false
},
// The marker hasn't expired yet.
Ok(false) => { true }
// The marker is missing or inaccessible in some way.
Err(_) => { false }
}
}
fn mark_negcache(path: &str) {
let miss_indicator = path.to_owned() + ".miss";
File::create(&miss_indicator).expect("Error creating negative cache marker");
}
fn icon_is_expired(path: &str) -> bool {
let expired = file_is_expired(path, CONFIG.icon_cache_ttl);
expired.unwrap_or(true)
}
fn get_icon_url(domain: &str) -> String { fn get_icon_url(domain: &str) -> String {
if CONFIG.local_icon_extractor { if CONFIG.local_icon_extractor {
format!("http://{}/favicon.ico", domain) format!("http://{}/favicon.ico", domain)