@ -18,6 +18,7 @@ use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState
pub enum PatchError {
NetworkError ( NetworkError ) ,
IOError ( std ::io ::Error ) ,
NoSuchClient ( ClientId ) ,
}
impl From < NetworkError > for PatchError {
@ -135,11 +136,11 @@ impl SendServerPacket for SendPatchPacket {
}
}
pub struct PatchServerState {
patch_file_tree : PatchFileTree ,
patch_file_lookup : HashMap < u32 , PatchFile > ,
patch_file_info : Vec < FileInfoReply > ,
client_file_info : HashMap < ClientId , Vec < FileInfoReply > > ,
patch_motd : String ,
}
@ -149,6 +150,7 @@ impl PatchServerState {
patch_file_tree ,
patch_file_lookup ,
patch_file_info : Vec ::new ( ) ,
client_file_info : HashMap ::new ( ) ,
patch_motd ,
}
}
@ -160,10 +162,11 @@ impl ServerState for PatchServerState {
type RecvPacket = RecvPatchPacket ;
type PacketError = PatchError ;
async fn on_connect ( & mut self , _ id : ClientId ) -> Result < Vec < OnConnect < Self ::SendPacket > > , PatchError > {
async fn on_connect ( & mut self , id : ClientId ) -> Result < Vec < OnConnect < Self ::SendPacket > > , PatchError > {
let mut rng = rand ::thread_rng ( ) ;
let key_in : u32 = rng . gen ( ) ;
let key_out : u32 = rng . gen ( ) ;
self . client_file_info . insert ( id , Vec ::new ( ) ) ;
Ok ( vec ! [ OnConnect ::Packet ( SendPatchPacket ::PatchWelcome ( PatchWelcome ::new ( key_out , key_in ) ) ) ,
OnConnect ::Cipher ( ( Box ::new ( PSOPCCipher ::new ( key_in ) ) , Box ::new ( PSOPCCipher ::new ( key_out ) ) ) )
@ -183,26 +186,39 @@ impl ServerState for PatchServerState {
Box ::new ( p . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) )
} ,
RecvPatchPacket ::FileInfoReply ( pkt ) = > {
self . patch_file_info . push ( pkt . clone ( ) ) ;
self . client_file_info . get_mut ( & id ) . ok_or ( PatchError ::NoSuchClient ( id ) ) ? . push ( pkt . clone ( ) ) ; // it should be impossible to error here under normal conditions?
// self.patch_file_info.push(pkt.clone());
// println!("PatchServerState.patch_file_info: {:?}", self.patch_file_info);
Box ::new ( None . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) )
} ,
RecvPatchPacket ::FileInfoListEnd ( _pkt ) = > {
let need_update = self . patch_file_info . iter ( )
. filter ( | file_info | does_file_need_updating ( file_info , & self . patch_file_lookup ) )
. collect ::< Vec < _ > > ( ) ;
let total_size = need_update . iter ( ) . fold ( 0 , | a , file_info | a + file_info . size ) ;
// let need_update = self.patch_file_info.iter()
// .filter(|file_info| does_file_need_updating(file_info, &self.patch_file_lookup))
// .collect::<Vec<_>>();
println ! ( "patch server hashmap: {:?}" , self . patch_file_lookup ) ;
let need_update = self . client_file_info . get ( & id )
. ok_or ( PatchError ::NoSuchClient ( id ) ) ?
. iter ( )
. filter ( | client_file_info | does_file_need_updating ( client_file_info , & self . patch_file_lookup ) )
. collect ::< Vec < _ > > ( ) ; // collecting list of `client_file_info`s. need to map these to the patch_files and collect those
println ! ( "ClientId({}) needs these files to be updated: {:?}" , id , need_update ) ;
// we have the file ids that need to be updated
let total_size = need_update . iter ( )
. filter_map ( | client_file | self . patch_file_lookup . get ( & client_file . id ) ) // TODO: dont unwrap?
. fold ( 0 , | a , file_info | a + file_info . size ) ;
let total_files = need_update . len ( ) as u32 ;
println ! ( "client {} needs {} bytes of updates across {} files" , id , total_size , total_files ) ;
let p = vec ! [ SendPatchPacket ::FilesToPatchMetadata ( FilesToPatchMetadata ::new ( total_size , total_files ) ) ,
SendPatchPacket ::PatchStartList ( PatchStartList { } )
] ;
Box ::new ( p . into_iter ( ) . chain ( SendFileIterator ::new ( self ) ) . map ( move | pkt | ( id , pkt ) ) )
println ! ( "p: {:?}" , p ) ;
Box ::new ( p . into_iter ( ) . chain ( SendFileIterator ::new ( self , need_update ) ) . map ( move | pkt | ( id , pkt ) ) )
}
} )
}
async fn on_disconnect ( & mut self , _id : ClientId ) -> Result < Vec < ( ClientId , SendPatchPacket ) > , PatchError > {
async fn on_disconnect ( & mut self , id : ClientId ) -> Result < Vec < ( ClientId , SendPatchPacket ) > , PatchError > {
self . client_file_info . remove ( & id ) ;
Ok ( Vec ::new ( ) )
}
}
@ -279,9 +295,10 @@ fn get_checksum_and_size(path: &Path) -> Result<(u32, u32), PatchError> {
Ok ( ( crc . sum32 ( ) , size as u32 ) )
}
fn does_file_need_updating ( file_info : & FileInfoReply , patch_file_lookup : & HashMap < u32 , PatchFile > ) -> bool {
let patch_file = patch_file_lookup . get ( & file_info . id ) . unwrap ( ) ;
patch_file . checksum ! = file_info . checksum | | patch_file . size ! = file_info . size
fn does_file_need_updating ( client_file_info : & FileInfoReply , patch_file_lookup : & HashMap < u32 , PatchFile > ) -> bool {
let patch_file = patch_file_lookup . get ( & client_file_info . id ) . unwrap ( ) ;
println ! ( "checking if client_file {:?} and patch_file {:?} need to be updated" , client_file_info , patch_file ) ;
patch_file . checksum ! = client_file_info . checksum | | patch_file . size ! = client_file_info . size
}
@ -294,9 +311,13 @@ struct SendFileIterator {
}
impl SendFileIterator {
fn new ( state : & PatchServerState ) -> SendFileIterator {
let file_ids_to_update = state . patch_file_info . iter ( )
. filter ( | file_info | does_file_need_updating ( file_info , & state . patch_file_lookup ) )
fn new ( state : & PatchServerState , client_file_info : Vec < & FileInfoReply > ) -> SendFileIterator {
// let file_ids_to_update = state.patch_file_info.iter()
// .filter(|file_info| does_file_need_updating(file_info, &state.patch_file_lookup))
// .map(|k| k.id)
// .collect::<HashSet<_>>();
let file_ids_to_update = client_file_info . iter ( )
. map ( | k | k . id )
. collect ::< HashSet < _ > > ( ) ;