2019-04-20 01:24:19 +02:00
// TODO: remove on implementation
#![ allow(unused_imports) ]
#![ allow(unused_variables) ]
#![ allow(dead_code) ]
use crate ::model ::* ;
use std ::collections ::HashMap ;
2019-04-30 19:08:40 +02:00
use std ::fs ;
2019-04-20 01:24:19 +02:00
use std ::io ;
use std ::path ::{ Path , PathBuf } ;
use std ::sync ::Arc ;
2019-05-04 18:35:49 +02:00
use sha2 ::{ self , Digest } ;
2019-04-20 01:24:19 +02:00
pub use self ::search ::Query ;
2019-04-30 19:08:40 +02:00
mod collection_file ;
2019-04-20 01:24:19 +02:00
mod image_convert ;
2019-04-24 17:01:43 +02:00
mod search ;
2019-04-20 01:24:19 +02:00
2019-04-24 17:01:43 +02:00
pub type TextureFileResult = Result < Arc < Vec < u8 > > , TextureFileError > ;
2019-04-20 01:24:19 +02:00
pub enum TextureFileError {
NotFound ,
IoError ( io ::Error ) ,
ImageError ( ::image ::ImageError ) ,
}
pub struct DataStore {
// private attributes
// may change
data_dir : PathBuf ,
texture : Vec < Texture > ,
preview_cache : HashMap < ( TextureFormat , Sha256 ) , Arc < Vec < u8 > > > ,
}
2019-05-04 18:35:49 +02:00
fn sha256 ( data : & [ u8 ] ) -> Sha256 {
let mut hasher = sha2 ::Sha256 ::new ( ) ;
hasher . input ( data ) ;
let hash_result = hasher . result ( ) ;
let hash_slice = hash_result . as_slice ( ) ;
let mut hash_arr = [ 0 u8 ; 32 ] ;
for i in 0 .. 32 {
hash_arr [ i ] = hash_slice [ i ] ;
}
Sha256 ( hash_arr )
}
2019-04-20 01:24:19 +02:00
impl DataStore {
pub fn new ( path : & Path ) -> io ::Result < DataStore > {
2019-04-30 19:08:40 +02:00
let base_path = path . to_path_buf ( ) ;
let mut collection_file_path = base_path . clone ( ) ;
collection_file_path . push ( " collection.json " ) ;
Ok ( DataStore {
data_dir : base_path ,
texture : collection_file ::load_collection_file ( & collection_file_path ) ? ,
preview_cache : HashMap ::new ( ) ,
} )
2019-04-20 01:24:19 +02:00
}
pub fn garbage_collect ( & mut self ) -> io ::Result < ( ) > {
unimplemented! ( )
}
pub fn query ( & mut self , query : & self ::search ::Query ) -> Vec < Texture > {
unimplemented! ( ) ;
// calls self::search::search(... )
}
/// returns true if successful
pub fn delete ( & mut self , tex : & Texture ) -> bool {
2019-04-30 19:08:40 +02:00
// Find the texture
let pos = self . texture . iter ( ) . position ( | e | e = = tex ) ;
match pos {
// Remove it
Some ( idx ) = > {
let removed = self . texture . remove ( idx ) ;
2019-05-03 15:02:40 +02:00
let mut key = ( TextureFormat ::PNG , removed . texture_hash ) ;
self . preview_cache . remove ( & key ) ; // Delete png preview
key . 0 = TextureFormat ::JPEG ;
self . preview_cache . remove ( & key ) ; // Delete jpeg preview
2019-04-30 19:08:40 +02:00
true
}
// Texture not found
None = > false ,
}
2019-04-20 01:24:19 +02:00
}
2019-05-03 11:19:34 +02:00
/// * `data` The content of the texture file, if available.
pub fn insert (
& mut self ,
tex : Texture ,
data : Option < Arc < Vec < u8 > > > ,
2019-05-03 13:56:08 +02:00
) -> ProtocolResult < ReplaceTextureStatus > {
2019-05-03 11:19:34 +02:00
use io ::Write ;
2019-04-30 19:08:40 +02:00
// Check for collisions
2019-05-03 11:19:34 +02:00
if self
2019-04-30 19:08:40 +02:00
. texture
. iter ( )
2019-05-03 11:19:34 +02:00
. find ( | e | e . id = = tex . id | | e . name = = tex . name )
. is_some ( )
{
// Name or id already in use
2019-05-03 13:56:08 +02:00
Err ( ProtocolError ::Conflict (
" Name or id is already in use. " . to_string ( ) ,
) )
2019-05-03 11:19:34 +02:00
} else {
2019-04-30 19:08:40 +02:00
// Insert it
2019-05-03 11:19:34 +02:00
if self . has_hash ( & tex . texture_hash ) ? {
2019-04-30 19:08:40 +02:00
self . texture . push ( tex ) ;
2019-05-03 11:19:34 +02:00
Ok ( ReplaceTextureStatus ::Ok )
} else {
match data {
None = > Ok ( ReplaceTextureStatus ::NeedTextureData ( tex . texture_hash ) ) ,
Some ( blob ) = > {
2019-05-04 18:35:49 +02:00
if sha256 ( & blob ) ! = tex . texture_hash {
return Err ( ProtocolError ::BadRequest (
" The texture does not have the given hash value. " . to_string ( ) ,
) ) ;
}
2019-05-03 11:19:34 +02:00
let mut tmp_image_path = self . data_dir . clone ( ) ;
tmp_image_path . push ( " textures " ) ;
tmp_image_path . push ( format! (
" {}_new " ,
tex . texture_hash . create_hex_string ( ) . to_lowercase ( )
) ) ;
let mut final_image_path = self . data_dir . clone ( ) ;
final_image_path . push ( " textures " ) ;
final_image_path . push ( tex . texture_hash . create_hex_string ( ) . to_lowercase ( ) ) ;
{
let mut writer = fs ::File ::create ( & tmp_image_path ) ? ;
writer . write_all ( & blob ) ? ;
}
fs ::rename ( tmp_image_path , final_image_path ) ? ;
Ok ( ReplaceTextureStatus ::Ok )
}
}
2019-04-30 19:08:40 +02:00
}
}
2019-04-20 01:24:19 +02:00
}
pub fn by_name < ' a > ( & ' a self , name : & str ) -> Option < & ' a Texture > {
2019-05-03 11:19:34 +02:00
self . texture . iter ( ) . find ( | e | e . name = = name )
2019-04-20 01:24:19 +02:00
}
pub fn by_id < ' a , ' b > ( & ' a self , id : & ' b str ) -> Option < & ' a Texture > {
2019-05-03 11:19:34 +02:00
self . texture . iter ( ) . find ( | e | e . id = = id )
2019-04-20 01:24:19 +02:00
}
2019-05-03 11:19:34 +02:00
/// Check if the texture, given by hash, physically exists on the file system.
pub fn has_hash ( & self , hash : & Sha256 ) -> io ::Result < bool > {
let mut texture_path = self . data_dir . clone ( ) ;
texture_path . push ( " textures " ) ;
texture_path . push ( hash . create_hex_string ( ) . to_lowercase ( ) ) ;
match texture_path . metadata ( ) {
Ok ( meta ) = > {
if meta . is_file ( ) {
Ok ( true )
} else {
Err ( io ::Error ::new (
io ::ErrorKind ::Other ,
format! ( " {:?} exists but is not a regular file. " , texture_path ) ,
) )
}
}
Err ( e ) = > {
if e . kind ( ) = = io ::ErrorKind ::NotFound {
Ok ( false )
} else {
Err ( e )
}
}
}
2019-04-20 01:24:19 +02:00
}
pub fn get_texture_file ( & mut self , hash : & Sha256 ) -> TextureFileResult {
2019-04-30 19:08:40 +02:00
use io ::Read ;
let mut file_path = self . data_dir . clone ( ) ;
file_path . push ( " textures " ) ;
file_path . push ( hash . create_hex_string ( ) . to_lowercase ( ) ) ;
let mut file = match fs ::File ::open ( file_path ) {
Ok ( f ) = > f ,
Err ( e ) = > {
if e . kind ( ) = = io ::ErrorKind ::NotFound {
return Err ( TextureFileError ::NotFound ) ;
} else {
return Err ( TextureFileError ::IoError ( e ) ) ;
}
}
} ;
let mut buffer = Vec ::new ( ) ;
match file . read_to_end ( & mut buffer ) {
Ok ( _ ) = > ( ) ,
Err ( e ) = > return Err ( TextureFileError ::IoError ( e ) ) ,
} ;
Ok ( Arc ::new ( buffer ) )
2019-04-20 01:24:19 +02:00
}
pub fn get_texture_preview ( & mut self , hash : & Sha256 ) -> TextureFileResult {
unimplemented! ( ) ;
}
2019-05-04 18:35:49 +02:00
fn store_metadata ( & self ) -> io ::Result < ( ) > {
let mut tmp_path = self . data_dir . clone ( ) ;
tmp_path . push ( " collection_new.json " ) ;
collection_file ::store_collection_file ( & tmp_path , & self . texture ) ? ;
let mut final_path = self . data_dir . clone ( ) ;
final_path . push ( " collection.json " ) ;
fs ::rename ( tmp_path , final_path )
}
2019-04-20 01:24:19 +02:00
}