|
|
@ -17,16 +17,16 @@ use elseware::pktvec; |
|
|
|
use elseware::common::pktvec::PktVec;
|
|
|
|
use elseware::common::network::{PacketNetworkError};
|
|
|
|
use elseware::common::client::Client;
|
|
|
|
use elseware::common::serverstate::{ServerPacket, ServerState, OnConnect};
|
|
|
|
use elseware::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
|
|
|
|
|
|
|
const PATCH_PORT: u16 = 11000;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum PatchError {
|
|
|
|
PacketNetworkError(PacketNetworkError),
|
|
|
|
UnexpectedPacket(Box<dyn PSOPacket>),
|
|
|
|
//UnexpectedPacket(Box<dyn PSOPacket>),
|
|
|
|
IOError(std::io::Error),
|
|
|
|
CloseConnection,
|
|
|
|
//CloseConnection,
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: something like
|
|
|
@ -93,25 +93,63 @@ impl PatchFileTree { |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum PatchPacket {
|
|
|
|
pub enum RecvPatchPacket {
|
|
|
|
PatchWelcomeReply(PatchWelcomeReply),
|
|
|
|
LoginReply(LoginReply),
|
|
|
|
FileInfoReply(FileInfoReply),
|
|
|
|
FileInfoListEnd(FileInfoListEnd),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ServerPacket for PatchPacket {
|
|
|
|
fn from_bytes(data: &Vec<u8>) -> Result<PatchPacket, PacketParseError> {
|
|
|
|
impl RecvServerPacket for RecvPatchPacket {
|
|
|
|
fn from_bytes(data: &Vec<u8>) -> Result<RecvPatchPacket, PacketParseError> {
|
|
|
|
match data[2] {
|
|
|
|
0x02 => Ok(PatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)),
|
|
|
|
0x04 => Ok(PatchPacket::LoginReply(LoginReply::from_bytes(data)?)),
|
|
|
|
0x0F => Ok(PatchPacket::FileInfoReply(FileInfoReply::from_bytes(data)?)),
|
|
|
|
0x10 => Ok(PatchPacket::FileInfoListEnd(FileInfoListEnd::from_bytes(data)?)),
|
|
|
|
0x02 => Ok(RecvPatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)),
|
|
|
|
0x04 => Ok(RecvPatchPacket::LoginReply(LoginReply::from_bytes(data)?)),
|
|
|
|
0x0F => Ok(RecvPatchPacket::FileInfoReply(FileInfoReply::from_bytes(data)?)),
|
|
|
|
0x10 => Ok(RecvPatchPacket::FileInfoListEnd(FileInfoListEnd::from_bytes(data)?)),
|
|
|
|
_ => Err(PacketParseError::WrongPacketForServerType)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum SendPatchPacket {
|
|
|
|
ChangeDirectory(ChangeDirectory),
|
|
|
|
EndFileSend(EndFileSend),
|
|
|
|
FileInfo(FileInfo),
|
|
|
|
FileSend(FileSend),
|
|
|
|
FilesToPatchMetadata(FilesToPatchMetadata),
|
|
|
|
FinalizePatching(FinalizePatching),
|
|
|
|
Message(Message),
|
|
|
|
PatchEndList(PatchEndList),
|
|
|
|
PatchStartList(PatchStartList),
|
|
|
|
PatchWelcome(PatchWelcome),
|
|
|
|
RequestLogin(RequestLogin),
|
|
|
|
StartFileSend(StartFileSend),
|
|
|
|
UpOneDirectory(UpOneDirectory),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SendServerPacket for SendPatchPacket {
|
|
|
|
fn as_bytes(&self) -> Vec<u8> {
|
|
|
|
match self {
|
|
|
|
SendPatchPacket::ChangeDirectory(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::EndFileSend(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::FileInfo(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::FileSend(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::FilesToPatchMetadata(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::FinalizePatching(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::Message(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::PatchEndList(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::PatchStartList(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::PatchWelcome(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::RequestLogin(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::StartFileSend(pkt) => pkt.as_bytes(),
|
|
|
|
SendPatchPacket::UpOneDirectory(pkt) => pkt.as_bytes(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct PatchServerState {
|
|
|
|
patch_file_tree: PatchFileTree,
|
|
|
|
patch_file_lookup: HashMap<u32, PatchFile>,
|
|
|
@ -129,35 +167,36 @@ impl PatchServerState { |
|
|
|
}
|
|
|
|
|
|
|
|
impl ServerState for PatchServerState {
|
|
|
|
type Packet = PatchPacket;
|
|
|
|
type SendPacket = SendPatchPacket;
|
|
|
|
type RecvPacket = RecvPatchPacket;
|
|
|
|
type PacketError = PatchError;
|
|
|
|
|
|
|
|
fn on_connect(&mut self) -> Vec<OnConnect> {
|
|
|
|
fn on_connect(&mut self) -> Vec<OnConnect<Self::SendPacket>> {
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let key_in: u32 = rng.gen();
|
|
|
|
let key_out: u32 = rng.gen();
|
|
|
|
|
|
|
|
vec![OnConnect::Packet(Box::new(PatchWelcome::new(key_out, key_in))),
|
|
|
|
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))))
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle(&mut self, pkt: &PatchPacket) -> Box<dyn Iterator<Item = Box<dyn PSOPacket>>> {
|
|
|
|
fn handle(&mut self, pkt: &RecvPatchPacket) -> Box<dyn Iterator<Item = SendPatchPacket>> {
|
|
|
|
match pkt {
|
|
|
|
PatchPacket::PatchWelcomeReply(_pkt) => {
|
|
|
|
pktvec![RequestLogin {}]
|
|
|
|
RecvPatchPacket::PatchWelcomeReply(_pkt) => {
|
|
|
|
Box::new(vec![SendPatchPacket::RequestLogin(RequestLogin {})].into_iter())
|
|
|
|
},
|
|
|
|
PatchPacket::LoginReply(_pkt) => {
|
|
|
|
let mut p = pktvec![Message::new("hello player".to_string())];
|
|
|
|
p.append(get_file_list_packets(&self.patch_file_tree));
|
|
|
|
p.push(Box::new(PatchEndList {}));
|
|
|
|
p
|
|
|
|
RecvPatchPacket::LoginReply(_pkt) => {
|
|
|
|
let mut p = vec![SendPatchPacket::Message(Message::new("hello player".to_string()))];
|
|
|
|
p.append(&mut get_file_list_packets(&self.patch_file_tree));
|
|
|
|
p.push(SendPatchPacket::PatchEndList(PatchEndList {}));
|
|
|
|
Box::new(p.into_iter())
|
|
|
|
},
|
|
|
|
PatchPacket::FileInfoReply(pkt) => {
|
|
|
|
RecvPatchPacket::FileInfoReply(pkt) => {
|
|
|
|
self.patch_file_info.push(pkt.clone());
|
|
|
|
Box::new(None.into_iter())
|
|
|
|
},
|
|
|
|
PatchPacket::FileInfoListEnd(_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<_>>();
|
|
|
@ -165,10 +204,10 @@ impl ServerState for PatchServerState { |
|
|
|
let total_size = need_update.iter().fold(0, |a, file_info| a + file_info.size);
|
|
|
|
let total_files = need_update.len() as u32;
|
|
|
|
|
|
|
|
let p = pktvec![FilesToPatchMetadata::new(total_size, total_files),
|
|
|
|
PatchStartList {}
|
|
|
|
let p = vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)),
|
|
|
|
SendPatchPacket::PatchStartList(PatchStartList {})
|
|
|
|
];
|
|
|
|
Box::new(p.chain(SendFileIterator::new(&self)))
|
|
|
|
Box::new(p.into_iter().chain(SendFileIterator::new(&self)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -211,19 +250,19 @@ fn generate_patch_tree(basedir: &str) -> (PatchFileTree, HashMap<u32, PatchFile> |
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec<Box<dyn PSOPacket>> {
|
|
|
|
let mut pkts: Vec<Box<dyn PSOPacket>> = Vec::new();
|
|
|
|
fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec<SendPatchPacket> {
|
|
|
|
let mut pkts = Vec::new();
|
|
|
|
|
|
|
|
for item in patch_file_tree.flatten() {
|
|
|
|
match item {
|
|
|
|
PatchTreeIterItem::Directory(path) => {
|
|
|
|
pkts.push(Box::new(ChangeDirectory::new(path.to_str().unwrap())));
|
|
|
|
pkts.push(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap())));
|
|
|
|
},
|
|
|
|
PatchTreeIterItem::File(path, id) => {
|
|
|
|
pkts.push(Box::new(FileInfo::new(path.to_str().unwrap(), id)));
|
|
|
|
pkts.push(SendPatchPacket::FileInfo(FileInfo::new(path.to_str().unwrap(), id)));
|
|
|
|
},
|
|
|
|
PatchTreeIterItem::UpDirectory => {
|
|
|
|
pkts.push(Box::new(UpOneDirectory {}));
|
|
|
|
pkts.push(SendPatchPacket::UpOneDirectory(UpOneDirectory {}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -281,7 +320,7 @@ impl SendFileIterator { |
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for SendFileIterator {
|
|
|
|
type Item = Box<dyn PSOPacket>;
|
|
|
|
type Item = SendPatchPacket;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if self.done {
|
|
|
@ -295,19 +334,19 @@ impl Iterator for SendFileIterator { |
|
|
|
if len == 0 {
|
|
|
|
self.current_file = None;
|
|
|
|
self.chunk_num = 0;
|
|
|
|
Some(Box::new(EndFileSend::new()))
|
|
|
|
Some(SendPatchPacket::EndFileSend(EndFileSend::new()))
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
let mut crc = crc32::Digest::new(crc32::IEEE);
|
|
|
|
crc.write(&buf[0..len]);
|
|
|
|
let pkt = FileSend {
|
|
|
|
let pkt = SendPatchPacket::FileSend(FileSend {
|
|
|
|
chunk_num: self.chunk_num,
|
|
|
|
checksum: crc.sum32(),
|
|
|
|
chunk_size: len as u32,
|
|
|
|
buffer: buf,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
self.chunk_num += 1;
|
|
|
|
Some(Box::new(pkt))
|
|
|
|
Some(pkt)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => {
|
|
|
@ -315,7 +354,7 @@ impl Iterator for SendFileIterator { |
|
|
|
Some(next_file) => {
|
|
|
|
match next_file {
|
|
|
|
PatchTreeIterItem::Directory(path) => {
|
|
|
|
Some(Box::new(ChangeDirectory::new(path.to_str().unwrap())))
|
|
|
|
Some(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap())))
|
|
|
|
},
|
|
|
|
PatchTreeIterItem::File(path, id) => {
|
|
|
|
if self.file_ids_to_update.contains(&id) {
|
|
|
@ -323,21 +362,21 @@ impl Iterator for SendFileIterator { |
|
|
|
let file = fs::File::open(&patch_file.path).unwrap();
|
|
|
|
let size = file.metadata().unwrap().len();
|
|
|
|
self.current_file = Some(io::BufReader::new(file));
|
|
|
|
Some(Box::new(StartFileSend::new(path.to_str().unwrap(), size as u32, id)))
|
|
|
|
Some(SendPatchPacket::StartFileSend(StartFileSend::new(path.to_str().unwrap(), size as u32, id)))
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
self.next()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PatchTreeIterItem::UpDirectory => {
|
|
|
|
Some(Box::new(UpOneDirectory {}))
|
|
|
|
Some(SendPatchPacket::UpOneDirectory(UpOneDirectory {}))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
self.current_file = None;
|
|
|
|
self.done = true;
|
|
|
|
Some(Box::new(FinalizePatching {}))
|
|
|
|
Some(SendPatchPacket::FinalizePatching(FinalizePatching {}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -353,8 +392,6 @@ fn new_client(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file |
|
|
|
client.io_loop();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
println!("[patch] starting server");
|
|
|
|
|
|
|
@ -390,6 +427,5 @@ fn main() { |
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
println!("[patch] exiting...");
|
|
|
|
}
|