You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
14 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. // Copyright 2016 Drew Short <drew@sothr.com>.
  2. //
  3. // Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
  4. // This file may not be copied, modified, or distributed except according to those terms.
  5. extern crate flate2;
  6. extern crate image;
  7. extern crate num;
  8. extern crate sha1;
  9. use self::flate2::Compression;
  10. use self::flate2::read::ZlibDecoder;
  11. use self::flate2::write::ZlibEncoder;
  12. use self::image::DynamicImage;
  13. use self::sha1::Sha1;
  14. use std::default::Default;
  15. use std::fs::{create_dir_all, File, remove_dir_all};
  16. use std::io::{Error, ErrorKind, Read, Write};
  17. use std::option::Option;
  18. use std::path::Path;
  19. use std::result::Result;
  20. use std::str::FromStr;
  21. use super::rustc_serialize::json;
  22. pub const DEFAULT_CACHE_DIR: &'static str = "./.hash_cache";
  23. const CACHED_IMAGE_EXT: &'static str = "png";
  24. const CACHED_MATRIX_EXT: &'static str = "dft";
  25. // Caching version information
  26. const CACHE_VERSION: u32 = 1;
  27. const CACHE_METADATA_FILE: &'static str = "cache.meta";
  28. #[derive(RustcDecodable, RustcEncodable)]
  29. struct CacheMetadata {
  30. cache_version: u32,
  31. }
  32. impl Default for CacheMetadata {
  33. fn default() -> CacheMetadata {
  34. CacheMetadata { cache_version: CACHE_VERSION }
  35. }
  36. }
  37. impl PartialEq<CacheMetadata> for CacheMetadata {
  38. fn eq(&self, other: &CacheMetadata) -> bool {
  39. self.cache_version == other.cache_version
  40. }
  41. fn ne(&self, other: &CacheMetadata) -> bool {
  42. !self.eq(&other)
  43. }
  44. }
  45. /**
  46. * Structure to hold implementation of the cache
  47. */
  48. #[repr(C)]
  49. pub struct Cache<'a> {
  50. pub cache_dir: &'a str,
  51. pub use_cache: bool,
  52. }
  53. impl<'a> Default for Cache<'a> {
  54. fn default() -> Cache<'a> {
  55. Cache {
  56. cache_dir: DEFAULT_CACHE_DIR,
  57. use_cache: true,
  58. }
  59. }
  60. }
  61. impl<'a> Cache<'a> {
  62. /**
  63. * Create the required directories for the cache
  64. */
  65. pub fn init(&self) -> Result<(), Error> {
  66. match create_dir_all(self.cache_dir) {
  67. Ok(_) => {
  68. let metadata_path_str = format!("{}/{}", self.cache_dir, CACHE_METADATA_FILE);
  69. let metadata_path = Path::new(&metadata_path_str);
  70. let current_metadata: CacheMetadata = Default::default();
  71. match File::open(&metadata_path) {
  72. Ok(mut file) => {
  73. // Metadata file exists, compare them
  74. let mut loaded_metadata_string = String::new();
  75. match file.read_to_string(&mut loaded_metadata_string) {
  76. Ok(_) => {
  77. let loaded_metadata: CacheMetadata =
  78. match json::decode(&loaded_metadata_string) {
  79. Ok(data) => data,
  80. Err(_) => CacheMetadata { cache_version: 0 },
  81. };
  82. // If they match, continue
  83. if current_metadata != loaded_metadata {
  84. // If they don't wipe the cache to start new
  85. match remove_dir_all(self.cache_dir) {
  86. Ok(_) => {
  87. match create_dir_all(self.cache_dir) {
  88. Ok(_) => (),
  89. Err(e) => println!("Error: {}", e),
  90. }
  91. }
  92. Err(e) => println!("Error: {}", e),
  93. };
  94. };
  95. }
  96. Err(e) => println!("Error: {}", e),
  97. };
  98. }
  99. // Metadata file doesn't exist, do nothing assume all is well,
  100. // create new metadata file
  101. Err(_) => {}
  102. };
  103. let encoded_cache_metadata = json::encode(&current_metadata).unwrap();
  104. match File::create(&metadata_path) {
  105. Ok(mut file) => {
  106. let _ = file.write(&encoded_cache_metadata.as_bytes());
  107. Ok(())
  108. }
  109. Err(e) => Err(e),
  110. }
  111. }
  112. Err(e) => Err(e),
  113. }
  114. }
  115. /**
  116. * Clean the cache directory completely
  117. */
  118. pub fn clean(&self) -> Result<(), Error> {
  119. remove_dir_all(self.cache_dir)
  120. }
  121. /**
  122. * Get the hash of the desired file and return it as a hex string
  123. */
  124. pub fn get_file_hash(&self, path: &Path) -> Result<String, Error> {
  125. let mut source = try!(File::open(&path));
  126. let mut buf: Vec<u8> = Vec::new();
  127. try!(source.read_to_end(&mut buf));
  128. let mut sha1 = Sha1::new();
  129. sha1.update(&buf);
  130. let digest = sha1.digest();
  131. // Return the hex result of the hash
  132. Ok(format!("{}", digest))
  133. }
  134. /**
  135. * Put an image buffer in the cache
  136. */
  137. pub fn put_image_in_cache(&self,
  138. path: &Path,
  139. size: u32,
  140. image: &DynamicImage)
  141. -> Result<bool, Error> {
  142. let hash = self.get_file_hash(&path);
  143. match hash {
  144. Ok(sha1) => {
  145. let cache_path_str = format!("{}/image/{}x{}/{}.{}",
  146. self.cache_dir,
  147. size,
  148. size,
  149. sha1,
  150. CACHED_IMAGE_EXT);
  151. let cache_dir_str = format!("{}/image/{}x{}", self.cache_dir, size, size);
  152. // println!("Saving: {}", cache_path_str);
  153. match create_dir_all(cache_dir_str) {
  154. Ok(_) => {
  155. match File::create(Path::new(&cache_path_str)) {
  156. Ok(mut file) => {
  157. // Save the file into the cache
  158. match image.save(& mut file, image::ImageFormat::PNG) {
  159. Ok(_) => {}
  160. Err(e) => {
  161. println ! ("Error: {}", e);
  162. return Err(Error::new(ErrorKind::Other, e));
  163. }
  164. }
  165. }
  166. Err(e) => return Err(e),
  167. }
  168. }
  169. Err(e) => return Err(e),
  170. }
  171. }
  172. Err(e) => {
  173. println!("Error: {}", e);
  174. return Err(e);
  175. }
  176. }
  177. Ok(true)
  178. }
  179. /**
  180. * Get an image buffer out of the cache
  181. */
  182. pub fn get_image_from_cache(&self,
  183. path: &Path,
  184. size: u32)
  185. -> Option<DynamicImage> {
  186. if self.use_cache {
  187. let hash = self.get_file_hash(&path);
  188. match hash {
  189. Ok(sha1) => {
  190. // Check if the file exists in the cache
  191. let cache_path_str = format!("{}/image/{}x{}/{}.{}",
  192. self.cache_dir,
  193. size,
  194. size,
  195. sha1,
  196. CACHED_IMAGE_EXT);
  197. let cached_path = Path::new(&cache_path_str);
  198. // Try to open, if it does, then we can read the image in
  199. match File::open(&cached_path) {
  200. Ok(_) => {
  201. let image = image::open(&cached_path).unwrap();
  202. Some(image)
  203. }
  204. // Don't really care here, it just means an existing cached
  205. // file doesn't exist, or can't be read.
  206. Err(_) => None,
  207. }
  208. }
  209. Err(e) => {
  210. println!("Error: {}", e);
  211. None
  212. }
  213. }
  214. } else {
  215. None
  216. }
  217. }
  218. /**
  219. * Expects a slice of slices that represents lines in the file
  220. */
  221. pub fn put_matrix_in_cache(&self,
  222. path: &Path,
  223. size: u32,
  224. file_contents: &Vec<Vec<f64>>)
  225. -> Result<bool, Error> {
  226. let hash = self.get_file_hash(&path);
  227. match hash {
  228. Ok(sha1) => {
  229. let cache_path_str = format!("{}/matrix/{}x{}/{}.{}",
  230. self.cache_dir,
  231. size,
  232. size,
  233. sha1,
  234. CACHED_MATRIX_EXT);
  235. let cache_dir_str = format!("{}/matrix/{}x{}", self.cache_dir, size, size);
  236. match create_dir_all(cache_dir_str) {
  237. Ok(_) => {
  238. let cached_path = Path::new(&cache_path_str);
  239. // Save the file into the cache
  240. match File::create(&cached_path) {
  241. Ok(mut file) => {
  242. let mut compressor = ZlibEncoder::new(Vec::new(),
  243. Compression::default());
  244. for row in file_contents {
  245. let mut row_str =
  246. row.iter()
  247. .fold(String::new(),
  248. |acc, &item| acc + &format!("{},", item));
  249. // remove the last comma
  250. let desire_len = row_str.len() - 1;
  251. row_str.truncate(desire_len);
  252. row_str.push_str("\n");
  253. try!(compressor.write(&row_str.into_bytes()));
  254. }
  255. let compressed_matrix = match compressor.finish() {
  256. Ok(data) => data,
  257. Err(e) => {
  258. println!("Unable to compress matrix data: {}", e);
  259. return Err(e);
  260. }
  261. };
  262. try!(file.write(&compressed_matrix));
  263. try!(file.flush());
  264. }
  265. Err(e) => {
  266. return Err(e);
  267. }
  268. }
  269. }
  270. Err(e) => println!("Error: {}", e),
  271. }
  272. }
  273. Err(e) => {
  274. println!("Error: {}", e);
  275. return Err(e);
  276. }
  277. }
  278. Ok(true)
  279. }
  280. /**
  281. * Get a matrix out of the cache
  282. */
  283. pub fn get_matrix_from_cache(&self, path: &Path, size: u32) -> Option<Vec<Vec<f64>>> {
  284. if self.use_cache {
  285. let hash = self.get_file_hash(&path);
  286. match hash {
  287. Ok(sha1) => {
  288. // Check if the file exists in the cache
  289. let cache_path_str = format!("{}/matrix/{}x{}/{}.{}",
  290. self.cache_dir,
  291. size,
  292. size,
  293. sha1,
  294. CACHED_MATRIX_EXT);
  295. let cached_path = Path::new(&cache_path_str);
  296. // Try to open, if it does, then we can read the image in
  297. match File::open(&cached_path) {
  298. Ok(file) => {
  299. let mut decoder = ZlibDecoder::new(&file);
  300. let mut matrix_data_str = String::new();
  301. match decoder.read_to_string(&mut matrix_data_str) {
  302. Ok(_) => {}
  303. Err(e) => {
  304. println!("Unable to decompress matrix: {}", e);
  305. return None;
  306. }
  307. };
  308. // convert the matrix
  309. let matrix: Vec<Vec<f64>> = matrix_data_str
  310. .trim()
  311. .split("\n")
  312. .map(|line| {
  313. line.split(",")
  314. .map(|f| f64::from_str(f).unwrap())
  315. .collect()
  316. })
  317. .collect();
  318. Some(matrix)
  319. }
  320. // Don't really care here, it just means an existing cached
  321. // file doesn't exist, or can't be read.
  322. Err(_) => None,
  323. }
  324. }
  325. Err(e) => {
  326. println!("Error: {}", e);
  327. None
  328. }
  329. }
  330. } else {
  331. None
  332. }
  333. }
  334. }
  335. #[test]
  336. fn test_get_file_hash() {
  337. let target = "test_images/sample_01_large.jpg";
  338. let target_path = Path::new(target);
  339. let cache: Cache = Default::default();
  340. let hash = cache.get_file_hash(&target_path);
  341. match hash {
  342. Ok(v) => {
  343. println!("Hash: {}", v);
  344. assert!(v == "4beb6f2d852b75a313863916a1803ebad13a3196");
  345. }
  346. Err(e) => {
  347. println!("Error: {:?}", e);
  348. assert!(false);
  349. }
  350. }
  351. }