1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
use std::net; use std::collections::hash_map::HashMap; use Cache; use Cache::Redis; use Result; use CacheError; use Cacheable; use CacheAccess; use redis; use redis::Commands; use dns_lookup::lookup_host; #[allow(dead_code)] pub struct RedisCache { client: redis::Client, connection: redis::Connection, } impl RedisCache { pub fn new(host: &str, password: Option<&str>) -> Result<Cache> { let host_vec: Vec<&str> = host.split(":").collect(); let ips: Vec<net::IpAddr> = match lookup_host(host_vec[0]) { Ok(hosts) => hosts, Err(e) => return Err(CacheError::Other(e.to_string())), }; let ip_host = if host_vec.len() > 1 { format!("{}:{}", ips[0].to_string(), host_vec[1]) } else { ips[0].to_string() }; let url = match password { Some(p) => format!("redis://:{}@{}", p, ip_host), None => format!("redis://{}", ip_host), }; let client = match redis::Client::open(url.as_str()) { Ok(c) => c, Err(e) => return Err(CacheError::Other(e.to_string())), }; let connection = match client.get_connection() { Ok(c) => c, Err(e) => return Err(CacheError::Other(e.to_string())), }; Ok(Redis(RedisCache { client, connection })) } } impl CacheAccess for RedisCache { fn insert<K: ToString, O: Cacheable + 'static>(&mut self, key: K, obj: O) -> Result<()> { let redis_key = redis_key_create::<K, O>(key); let data = obj.to_redis_obj(); redis_hash_set_multiple(&self.connection, redis_key, &data) } fn get<K: ToString, O: Cacheable + 'static>(&mut self, key: K) -> Option<O> { let redis_key = redis_key_create::<K, O>(key); if let Ok(val) = redis_hash_get_all(&self.connection, redis_key) { if let Ok(c) = O::from_redis_obj(val) { Some(c) } else { None } } else { None } } fn remove<K: ToString, O: Cacheable>(&mut self, key: K) -> Result<()> { let redis_key = redis_key_create::<K, O>(key); redis_delete(&self.connection, redis_key) } } fn redis_key_create<K: ToString, O: Cacheable>(key: K) -> String { let mut redis_key = String::from(O::model_name()); redis_key.push_str(":"); redis_key.push_str(key.to_string().as_str()); redis_key } fn redis_hash_set_multiple<F: redis::ToRedisArgs, V: redis::ToRedisArgs>(con: &redis::Connection, key: String, v: &[(F, V)]) -> Result<()> { match con.hset_multiple::<String, F, V, ()>(key, v) { Ok(_) => Ok(()), Err(_) => Err(CacheError::InsertionError(String::new())), } } fn redis_hash_get_all(con: &redis::Connection, key: String) -> Result<HashMap<String, String>> { match con.hgetall::<String, HashMap<String, String>>(key) { Ok(v) => Ok(v), Err(e) => Err(CacheError::Other(e.to_string())), } } fn redis_delete(con: &redis::Connection, key: String) -> Result<()> { match con.del::<String, ()>(key) { Ok(_) => Ok(()), Err(_) => Err(CacheError::DeletionError(String::new())), } }