rust-tcp-file-transfer/src/main.rs

320 lines
14 KiB
Rust
Raw Normal View History

2023-10-02 22:04:41 +03:00
use std::fs::{File, Metadata, self};
2023-09-17 07:28:18 +03:00
use std::time::Instant;
2023-09-14 08:29:32 +03:00
use std::net::{TcpListener, TcpStream};
2023-10-08 01:52:42 +03:00
use std::io::{Read, Write, self, BufReader};
2023-09-16 19:15:30 +03:00
use std::env::{self};
2023-09-14 08:29:32 +03:00
2023-09-16 19:15:30 +03:00
struct FileInfo
2023-09-14 08:29:32 +03:00
{
2023-09-16 19:15:30 +03:00
file:Option<File>,
2023-10-08 01:52:42 +03:00
reader:Option<BufReader<File>>,
2023-09-16 19:15:30 +03:00
location:String,
2023-10-08 01:52:42 +03:00
bytes_current:Vec<u8>,
size_current:usize,
size_total:Option<usize>,
2023-10-02 22:04:41 +03:00
metadata:Option<Metadata>,
2023-09-14 08:29:32 +03:00
}
2023-09-16 19:15:30 +03:00
impl FileInfo
2023-09-14 08:29:32 +03:00
{
2023-10-08 01:52:42 +03:00
fn reading_operations(&mut self, stream:&mut TcpStream)
2023-09-29 01:44:25 +03:00
{
2023-10-02 22:04:41 +03:00
self.read_metadata();
match self.metadata
{
Some(ref mut metadata) =>
{
if Metadata::is_file(metadata)
{
2023-10-08 01:52:42 +03:00
self.size_total = Some(Metadata::len(&metadata) as usize);
2023-10-02 22:04:41 +03:00
self.read_file();
}
else if Metadata::is_symlink(metadata)
{
2023-10-08 01:52:42 +03:00
self.size_total = Some(Metadata::len(&metadata) as usize);
2023-10-02 22:04:41 +03:00
self.read_file();
}
else
{
//path recognition and creation on the other side
//std:path
panic!("\n\tError: Folder Transfers've not Supported yet\n")
}
}
None =>
2023-10-08 01:52:42 +03:00
{
println!("Error: Read Metadata -> {}", self.location);
}
}
match self.size_total
{
Some(ref mut size_total) =>
2023-10-02 22:04:41 +03:00
{
2023-10-08 01:52:42 +03:00
self.file_to_byte(stream)
}
None =>
{
println!("Error: Read Size -> {}", self.location);
2023-10-02 22:04:41 +03:00
}
}
2023-09-29 01:44:25 +03:00
}
2023-10-08 01:52:42 +03:00
fn writing_operations(&mut self, stream:&mut TcpStream)
2023-09-29 01:44:25 +03:00
{
self.write_file();
}
2023-10-02 22:04:41 +03:00
fn read_metadata(&mut self)
{
2023-10-08 01:52:42 +03:00
//use match, there is a chance to fail creation. don't pass with just some
2023-10-02 22:04:41 +03:00
self.metadata = Some(fs::metadata(&self.location).expect("Error: Read Metadata"));
}
2023-09-16 19:15:30 +03:00
fn read_file(&mut self)
{
2023-10-08 01:52:42 +03:00
match File::open(&self.location)
{
Ok(file) =>
{
self.file = Some(file);
self.reader = Some(BufReader::new(file));
}
Err(err_val) =>
{
println!("Error: Open File -> {} | Error: {}", self.location, err_val);
}
}
2023-09-16 19:15:30 +03:00
}
2023-10-08 01:52:42 +03:00
fn file_to_byte(&mut self, stream:&mut TcpStream)
2023-09-16 19:15:30 +03:00
{
2023-10-08 01:52:42 +03:00
self.bytes_current.clear();
2023-09-16 19:15:30 +03:00
match self.file
{
Some(ref mut file_descriptor) =>
{
2023-10-08 01:52:42 +03:00
//replace with readbuffer ?
match self.reader
2023-09-16 19:15:30 +03:00
{
2023-10-08 01:52:42 +03:00
Some(reader) =>
2023-09-16 19:15:30 +03:00
{
2023-10-08 01:52:42 +03:00
// I don't know what to do
2023-09-16 19:15:30 +03:00
}
2023-10-08 01:52:42 +03:00
None =>
{
}
}
match File::read_exact(file_descriptor, &mut self.bytes_current)
{
Ok(_) =>
{
self.size_current = self.size_current+self.bytes_current.len();
//need to send data, or call here from connection
match stream.write_all(&self.bytes_current)
{
Ok(_) =>
{
// We will track when we stop later
}
Err(err_val) =>
{
println!("Error: Send -> {} | Error: {}", self.location, err_val)
}
}
if self.size_total == Some(self.size_current)
{
println!("Done: Read -> {} | Done: Read -> {} bytes", self.location, self.size_current);
}
else
{
self.file_to_byte(stream);
}
}
Err(err_val) => println!("Error: Read -> {} | Error: {}", self.location, err_val),
2023-09-16 19:15:30 +03:00
}
}
None =>
{
2023-10-08 01:52:42 +03:00
println!("Error: File None -> {}", self.location);
2023-09-16 19:15:30 +03:00
}
}
}
fn write_file(&mut self)
2023-09-14 08:29:32 +03:00
{
2023-10-08 01:52:42 +03:00
//use match, there is a chance to fail creation. don't pass with just some
2023-09-16 19:15:30 +03:00
self.file = Some(File::create(&self.location).expect("Error: Create File"));
match self.file
{
Some(ref mut file_descriptor) =>
{
2023-09-16 21:58:21 +03:00
match File::write_all(file_descriptor, &mut self.bytes)
2023-09-16 19:15:30 +03:00
{
2023-09-16 22:08:10 +03:00
Ok(_) =>
{
2023-10-08 01:52:42 +03:00
self.size_total = self.bytes.len();
2023-09-16 22:08:10 +03:00
println!("Done: Write -> {} bytes", &mut self.size);
}
2023-09-16 21:58:21 +03:00
Err(err_val) => println!("Error: Write {}", err_val),
2023-09-16 19:15:30 +03:00
}
}
None =>
{
println!("Error: File None");
}
}
2023-09-14 08:29:32 +03:00
}
}
2023-09-16 19:15:30 +03:00
enum Connection
{
Server(String, String),
Client(String, String),
}
impl Connection
2023-09-14 08:29:32 +03:00
{
2023-09-16 19:15:30 +03:00
fn server(self, file_info:&mut FileInfo)
{
2023-10-02 22:04:41 +03:00
print!("Server -> ");
2023-09-16 19:15:30 +03:00
let ip:String;
let port:String;
let address:String;
match self
{
Connection::Server(in1, in2) =>
{
ip = in1.trim_end().to_string();
port = in2.trim_end().to_string();
address = format!("{}:{}", ip, port);
println!("{}", address);
}
_ => return
}
let socket = TcpListener::bind(address);
for stream in socket.expect("Error: Can't Check Connections").incoming()
{
match stream
{
Ok(mut stream) =>
{
let stay = true;
while stay
{
let mut data = vec![];
2023-09-17 07:28:18 +03:00
let start_time = Instant::now();
2023-09-16 21:58:21 +03:00
match stream.read_to_end(&mut data)
2023-09-16 19:15:30 +03:00
{
Ok(res) =>
{
if res == 0
{
println!("Connection Closed");
return;
}
2023-09-16 21:58:21 +03:00
file_info.bytes = data;
2023-10-08 01:52:42 +03:00
FileInfo::writing_operations(file_info, &mut stream);
2023-09-17 07:28:18 +03:00
let finish_time = Instant::now();
println!("Passed: Total -> {:#?}", finish_time.duration_since(start_time));
2023-09-16 19:15:30 +03:00
}
Err(e) =>
{
println!("Error: Failed to Read -> {}", e);
return;
}
}
}
}
Err(e) =>
{
println!("Error: Can't Visit Stream -> {}", e);
return;
}
}
}
}
fn client(self, file_info:&mut FileInfo)
2023-09-14 08:29:32 +03:00
{
2023-10-02 22:04:41 +03:00
print!("Client -> ");
2023-09-16 19:15:30 +03:00
let ip:String;
let port:String;
let address:String;
match self
{
Connection::Client(in1, in2) =>
{
ip = in1.trim_end().to_string();
port = in2.trim_end().to_string();
address = format!("{}:{}", ip, port);
println!("{}", address);
}
_ => return
}
match TcpStream::connect(address)
{
2023-10-08 01:52:42 +03:00
Ok(mut stream) =>
2023-09-16 19:15:30 +03:00
{
2023-09-17 07:28:18 +03:00
let start_time = Instant::now();
2023-09-16 19:15:30 +03:00
println!("Connected");
2023-10-08 01:52:42 +03:00
FileInfo::reading_operations(file_info, &mut stream);
2023-09-17 07:28:18 +03:00
let finish_time = Instant::now();
println!("Passed: Total -> {:#?}", finish_time.duration_since(start_time));
2023-09-16 19:15:30 +03:00
}
Err(e) =>
{
println!("Error: Connection -> {}", e);
}
}
2023-09-14 08:29:32 +03:00
}
}
2023-09-16 19:15:30 +03:00
fn take_string(output:String) -> String
{
let mut input = String::new();
println!("{}", output);
2023-10-02 22:04:41 +03:00
io::stdin().read_line(&mut input).expect("Error: Failed to Read from Console");
2023-09-16 19:15:30 +03:00
input
}
fn take_arg() -> String
{
env::args().last().as_deref().unwrap_or("default").to_string()
}
2023-09-14 08:29:32 +03:00
fn main()
{
2023-10-02 22:04:41 +03:00
//DONT FORGET
//First we should check folder structure and validation then make connection.
2023-09-14 08:29:32 +03:00
println!("Hello, world!");
2023-09-16 19:15:30 +03:00
let mut data = FileInfo
{
file:None,
2023-10-08 01:52:42 +03:00
reader:None,
2023-09-16 19:15:30 +03:00
location:take_arg(),
2023-10-08 01:52:42 +03:00
bytes_current:Vec::with_capacity(1024),
size_current:0 as usize,
size_total:None,
2023-10-02 22:04:41 +03:00
metadata:None,
2023-09-16 19:15:30 +03:00
};
match &take_string("Input: Server 's', Client 'c'".to_string())[0..1]
{
"s" =>
{
Connection::server
(Connection::Server(take_string("Input: Server Stream IP Address".to_string()),
take_string("Input: Server Stream Port Address".to_string())),
&mut data);
},
"c" =>
{
Connection::client
(Connection::Client(take_string("Input: Server IP Address to Connect".to_string()),
take_string("Input: Server Port Address to Connect".to_string())),
&mut data);
}
input =>
{
println!("Error: Give Valid Input, You Gave : {}", input);
return;
}
}
2023-09-14 08:29:32 +03:00
}