| 
					
					
					
				 | 
				@ -1,20 +1,20 @@ | 
			
		
		
	
		
			
				 | 
				 | 
				//! This module contains structs for working with the github templates
 | 
				 | 
				 | 
				//! This module contains structs for working with the github templates
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				use directories::ProjectDirs;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				use crate::cache::Cache;
 | 
			
		
		
	
		
			
				 | 
				 | 
				use log::{debug, trace};
 | 
				 | 
				 | 
				use log::{debug, trace};
 | 
			
		
		
	
		
			
				 | 
				 | 
				use reqwest::blocking::Client;
 | 
				 | 
				 | 
				use reqwest::blocking::Client;
 | 
			
		
		
	
		
			
				 | 
				 | 
				use reqwest::header::{ACCEPT, CONTENT_TYPE, USER_AGENT};
 | 
				 | 
				 | 
				use reqwest::header::{ACCEPT, CONTENT_TYPE, USER_AGENT};
 | 
			
		
		
	
		
			
				 | 
				 | 
				use serde::{Deserialize, Serialize};
 | 
				 | 
				 | 
				use serde::{Deserialize, Serialize};
 | 
			
		
		
	
		
			
				 | 
				 | 
				use std::fs::File;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				use std::io::prelude::*;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				use std::io::{BufReader, BufWriter};
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				use std::path::PathBuf;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				use std::time::{Duration, SystemTime};
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				use crate::errors::*;
 | 
				 | 
				 | 
				use crate::errors::*;
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				type CacheContents = Vec<Template>;
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				type CacheType = dyn Cache<CacheContents>;
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				/// Default user agent string used for api requests
 | 
				 | 
				 | 
				/// Default user agent string used for api requests
 | 
			
		
		
	
		
			
				 | 
				 | 
				pub const DEFAULT_USER_AGENT: &str = "gitig";
 | 
				 | 
				 | 
				pub const DEFAULT_USER_AGENT: &str = "gitig";
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				/// Default key used for cache
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				const CACHE_KEY: &str = "templates.json";
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				/// Response objects from github api
 | 
				 | 
				 | 
				/// Response objects from github api
 | 
			
		
		
	
		
			
				 | 
				 | 
				#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 | 
				 | 
				 | 
				#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 | 
			
		
		
	
	
		
			
				| 
					
						
							
						
					
					
						
							
						
					
					
				 | 
				@ -65,9 +65,10 @@ impl Template { | 
			
		
		
	
		
			
				 | 
				 | 
				}
 | 
				 | 
				 | 
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				/// This struct holds the information about the templates available at github
 | 
				 | 
				 | 
				/// This struct holds the information about the templates available at github
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				#[derive(Serialize, Deserialize)]
 | 
			
		
		
	
		
			
				 | 
				 | 
				pub struct GithubTemplates {
 | 
				 | 
				 | 
				pub struct GithubTemplates {
 | 
			
		
		
	
		
			
				 | 
				 | 
				    /// The templates
 | 
				 | 
				 | 
				    /// The templates
 | 
			
		
		
	
		
			
				 | 
				 | 
				    templates: Vec<Template>,
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				    templates: CacheContents,
 | 
			
		
		
	
		
			
				 | 
				 | 
				}
 | 
				 | 
				 | 
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				impl GithubTemplates {
 | 
				 | 
				 | 
				impl GithubTemplates {
 | 
			
		
		
	
	
		
			
				| 
					
					
					
						
							
						
					
				 | 
				@ -82,70 +83,15 @@ impl GithubTemplates { | 
			
		
		
	
		
			
				 | 
				 | 
				            .header(USER_AGENT, format!("{} {}", DEFAULT_USER_AGENT, env!("CARGO_PKG_VERSION")))
 | 
				 | 
				 | 
				            .header(USER_AGENT, format!("{} {}", DEFAULT_USER_AGENT, env!("CARGO_PKG_VERSION")))
 | 
			
		
		
	
		
			
				 | 
				 | 
				            .send()
 | 
				 | 
				 | 
				            .send()
 | 
			
		
		
	
		
			
				 | 
				 | 
				            .chain_err(|| "Error while sending request to query all templates")?;
 | 
				 | 
				 | 
				            .chain_err(|| "Error while sending request to query all templates")?;
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				        let body: Vec<Template> = res.json().chain_err(|| "json")?;
 | 
				 | 
				 | 
				        let body: Vec<Template> = res.json().chain_err(|| "json")?;
 | 
			
		
		
	
		
			
				 | 
				 | 
				        debug!("Received and deserialized {} templates", body.len());
 | 
				 | 
				 | 
				        debug!("Received and deserialized {} templates", body.len());
 | 
			
		
		
	
		
			
				 | 
				 | 
				        trace!("Serializing templates to file cache");
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let cache = File::create(Self::cache_path())
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .chain_err(|| "Error while creating file cache to write")?;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let writer = BufWriter::new(cache);
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        serde_json::to_writer(writer, &body)
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .chain_err(|| "Error while serialzing templates to file cache")?;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        debug!("Serialization of templates completed");
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        Ok(GithubTemplates { templates: body })
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    /// Returns whether there is an cached json version
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    fn is_cached() -> bool {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let path = Self::cache_path();
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        if !path.exists() {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            return false;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let modified: SystemTime = path
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .metadata()
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .map(|meta| meta.modified().unwrap_or(SystemTime::UNIX_EPOCH))
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .unwrap_or(SystemTime::UNIX_EPOCH);
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let max_age = Duration::from_secs(60 * 24 * 2 /* two days */);
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        if modified.elapsed().unwrap_or(Duration::from_secs(u64::max_value())) > max_age {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            debug!("Cache file is too older (> days), won't be used");
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            return false;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				        true
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    /// Returns the path of the file cache
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    fn cache_path() -> PathBuf {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let proj = ProjectDirs::from("org", "webschneider", env!("CARGO_PKG_NAME"));
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let mut cache: PathBuf = match proj {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            Some(p) => p.cache_dir().into(),
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            None => PathBuf::from("/tmp"),
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        };
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        cache.push("templates.json");
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        debug!("Using cache path for templates: {}", cache.to_str().unwrap_or("err"));
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        cache
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    /// Reads the templates from the file cache
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				    fn from_cache() -> Result<GithubTemplates> {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        trace!("Reading templates from file cache");
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        if !Self::is_cached() {
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            debug!("Templates response not yet cached");
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            return Err("Results are not yet cached".into());
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let f = File::open(Self::cache_path())
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .chain_err(|| "Error while opening cache file for templates")?;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let reader = BufReader::new(f);
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        let tpls: Vec<Template> = serde_json::from_reader(reader)
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				            .chain_err(|| "Error while reading templates from file cache")?;
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        debug!("Deserialized {} templates from file cache", tpls.len());
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				        Ok(GithubTemplates { templates: tpls })
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				        Ok(GithubTemplates { templates: body })
 | 
			
		
		
	
		
			
				 | 
				 | 
				    }
 | 
				 | 
				 | 
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				    /// Creates a new struct with templates
 | 
				 | 
				 | 
				    /// Creates a new struct with templates
 | 
			
		
		
	
		
			
				 | 
				 | 
				    pub fn new() -> Result<GithubTemplates> { Self::from_cache().or_else(|_| Self::from_server()) }
 | 
				 | 
				 | 
				 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				    pub fn new() -> Result<GithubTemplates> { Self::from_server() }
 | 
			
		
		
	
		
			
				 | 
				 | 
				
 | 
				 | 
				 | 
				
 | 
			
		
		
	
		
			
				 | 
				 | 
				    /// Returns a list of the template names
 | 
				 | 
				 | 
				    /// Returns a list of the template names
 | 
			
		
		
	
		
			
				 | 
				 | 
				    pub fn list_names(&self) -> Vec<&str> {
 | 
				 | 
				 | 
				    pub fn list_names(&self) -> Vec<&str> {
 | 
			
		
		
	
	
		
			
				| 
					
						
							
						
					
					
					
				 | 
				
  |