mirror of
https://github.com/CompeyDev/ruck.git
synced 2025-01-08 11:49:09 +00:00
Cleanup
This commit is contained in:
parent
02f5fca565
commit
1c321301fd
5 changed files with 59 additions and 28 deletions
23
README.md
23
README.md
|
@ -2,11 +2,22 @@
|
||||||
|
|
||||||
`ruck` is a command line tool used for hosting relay servers and sending end-to-end encrypted files between clients. It was heavily inspired by [croc](https://github.com/schollz/croc), one of the easiest ways to send files between peers. This document describes the protocol `ruck` uses to support this functionality.
|
`ruck` is a command line tool used for hosting relay servers and sending end-to-end encrypted files between clients. It was heavily inspired by [croc](https://github.com/schollz/croc), one of the easiest ways to send files between peers. This document describes the protocol `ruck` uses to support this functionality.
|
||||||
|
|
||||||
### Version
|
## Usage
|
||||||
|
|
||||||
This document refers to version `0.1.0` of `ruck` as defined by the `Cargo.toml` file.
|
```bash
|
||||||
|
## tab 1
|
||||||
|
cargo run relay # this starts the server
|
||||||
|
|
||||||
## Server
|
## tab 2
|
||||||
|
cargo run send /path/to/file1.md /path/to/file2.md supersecretpassword
|
||||||
|
|
||||||
|
## tab 3
|
||||||
|
cargo run receive supersecretpassword
|
||||||
|
```
|
||||||
|
|
||||||
|
## Protocol
|
||||||
|
|
||||||
|
### Server
|
||||||
|
|
||||||
The server in `ruck` exposes a TCP port.
|
The server in `ruck` exposes a TCP port.
|
||||||
Its only functions are to staple connections and shuttle bytes between stapled connections.
|
Its only functions are to staple connections and shuttle bytes between stapled connections.
|
||||||
|
@ -19,7 +30,7 @@ The time out is set to remove idle connections.
|
||||||
The server does nothing else with the bytes, so the clients are free to end-to-end encrypt their messages.
|
The server does nothing else with the bytes, so the clients are free to end-to-end encrypt their messages.
|
||||||
For this reason, updates to the `ruck` protocol do not typically necessitate server redeployments.
|
For this reason, updates to the `ruck` protocol do not typically necessitate server redeployments.
|
||||||
|
|
||||||
## Client
|
### Client
|
||||||
|
|
||||||
There are two types of clients - `send` and `receive` clients.
|
There are two types of clients - `send` and `receive` clients.
|
||||||
Out of band, the clients agree on a relay server and password, from which they can derive the 32 byte identifier used by the server to staple their connections.
|
Out of band, the clients agree on a relay server and password, from which they can derive the 32 byte identifier used by the server to staple their connections.
|
||||||
|
@ -29,7 +40,5 @@ Once the handshake is complete, `send` and `receive` negotiate and exchange file
|
||||||
|
|
||||||
- `send` offers a list of files and waits.
|
- `send` offers a list of files and waits.
|
||||||
- `receive` specifies which bytes it wants from these files.
|
- `receive` specifies which bytes it wants from these files.
|
||||||
- `send` sends the specified bytes and waits.
|
- `send` sends the specified bytes, then a completion message and hangs up.
|
||||||
- `receive` sends heartbeats with progress updates.
|
|
||||||
- `send` hangs up once the heartbeats stop or received a successful heartbeat.
|
|
||||||
- `receive` hangs up once the downloads are complete.
|
- `receive` hangs up once the downloads are complete.
|
||||||
|
|
|
@ -96,8 +96,8 @@ pub async fn request_specific_files(conn: &mut Connection) -> Result<Vec<StdFile
|
||||||
pub async fn create_or_find_files(desired_files: Vec<FileOffer>) -> Result<Vec<StdFileHandle>> {
|
pub async fn create_or_find_files(desired_files: Vec<FileOffer>) -> Result<Vec<StdFileHandle>> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for desired_file in desired_files {
|
for desired_file in desired_files {
|
||||||
let mut filename = desired_file.path;
|
let filename = desired_file.path;
|
||||||
filename.push_str(".part");
|
// filename.push_str(".part");
|
||||||
let file = match File::open(filename.clone()).await {
|
let file = match File::open(filename.clone()).await {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
println!(
|
println!(
|
||||||
|
@ -106,16 +106,23 @@ pub async fn create_or_find_files(desired_files: Vec<FileOffer>) -> Result<Vec<S
|
||||||
);
|
);
|
||||||
file
|
file
|
||||||
}
|
}
|
||||||
Err(_) => File::create(filename).await?,
|
Err(_) => File::create(&filename).await?,
|
||||||
};
|
};
|
||||||
let metadata = file.metadata().await?;
|
let metadata = file.metadata().await?;
|
||||||
println!(
|
println!(
|
||||||
"Current len: {:?}, Full Size: {:?}",
|
"File: {:?}. Current len: {:?}, Full Size: {:?}",
|
||||||
|
filename.clone(),
|
||||||
metadata.len(),
|
metadata.len(),
|
||||||
desired_file.size
|
desired_file.size
|
||||||
);
|
);
|
||||||
let std_file_handle =
|
let std_file_handle = StdFileHandle::new(
|
||||||
StdFileHandle::new(desired_file.id, file, metadata.len(), desired_file.size).await?;
|
desired_file.id,
|
||||||
|
filename,
|
||||||
|
file,
|
||||||
|
metadata.len(),
|
||||||
|
desired_file.size,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
v.push(std_file_handle)
|
v.push(std_file_handle)
|
||||||
}
|
}
|
||||||
return Ok(v);
|
return Ok(v);
|
||||||
|
|
|
@ -81,12 +81,13 @@ impl Connection {
|
||||||
let elapsed = before.elapsed();
|
let elapsed = before.elapsed();
|
||||||
let mb_sent = bytes_sent / 1_048_576;
|
let mb_sent = bytes_sent / 1_048_576;
|
||||||
println!(
|
println!(
|
||||||
"{:?} mb sent, {:?} iterations. {:?} total time, {:?} avg per iteration, {:?} avg mb/sec",
|
"{:?}: {:?} mb sent (compressed), {:?} iterations. {:?} total time, {:?} avg per iteration, {:?} avg mb/sec",
|
||||||
|
handle.name,
|
||||||
mb_sent,
|
mb_sent,
|
||||||
count,
|
count,
|
||||||
elapsed,
|
elapsed,
|
||||||
elapsed / count,
|
elapsed / count,
|
||||||
mb_sent / elapsed.as_secs()
|
1000 * mb_sent as u128 / elapsed.as_millis()
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -112,7 +113,6 @@ impl Connection {
|
||||||
let msg = self.await_msg().await?;
|
let msg = self.await_msg().await?;
|
||||||
match msg {
|
match msg {
|
||||||
Message::FileTransfer(payload) => {
|
Message::FileTransfer(payload) => {
|
||||||
println!("In download");
|
|
||||||
if payload.chunk_header.id != handle.id {
|
if payload.chunk_header.id != handle.id {
|
||||||
return Err(anyhow!("Wrong file"));
|
return Err(anyhow!("Wrong file"));
|
||||||
}
|
}
|
||||||
|
@ -125,15 +125,19 @@ impl Connection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decoder.finish()?;
|
decoder.finish()?;
|
||||||
println!("Done downloading file.");
|
println!("Done downloading {:?}.", handle.name);
|
||||||
Connection::check_and_finish_download(clone, handle.size).await?;
|
Connection::check_and_finish_download(clone, handle.name, handle.size).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_and_finish_download(file: std::fs::File, size: u64) -> Result<()> {
|
pub async fn check_and_finish_download(
|
||||||
|
file: std::fs::File,
|
||||||
|
filename: String,
|
||||||
|
size: u64,
|
||||||
|
) -> Result<()> {
|
||||||
let metadata = file.metadata()?;
|
let metadata = file.metadata()?;
|
||||||
if metadata.len() == size {
|
if metadata.len() == size {
|
||||||
println!("File looks good.");
|
println!("OK: downloaded {:?} matches advertised size.", filename);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
|
|
25
src/file.rs
25
src/file.rs
|
@ -24,20 +24,25 @@ pub struct FileOffer {
|
||||||
|
|
||||||
pub struct StdFileHandle {
|
pub struct StdFileHandle {
|
||||||
pub id: u8,
|
pub id: u8,
|
||||||
|
pub name: String,
|
||||||
pub file: std::fs::File,
|
pub file: std::fs::File,
|
||||||
pub start: u64,
|
pub start: u64,
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdFileHandle {
|
impl StdFileHandle {
|
||||||
pub async fn new(id: u8, file: File, start: u64, size: u64) -> Result<StdFileHandle> {
|
pub async fn new(
|
||||||
|
id: u8,
|
||||||
|
name: String,
|
||||||
|
file: File,
|
||||||
|
start: u64,
|
||||||
|
size: u64,
|
||||||
|
) -> Result<StdFileHandle> {
|
||||||
let mut file = file.into_std().await;
|
let mut file = file.into_std().await;
|
||||||
file.seek(SeekFrom::Start(start))?;
|
file.seek(SeekFrom::Start(start))?;
|
||||||
if start != 0 {
|
|
||||||
println!("Seeking to {:?}", start);
|
|
||||||
}
|
|
||||||
Ok(StdFileHandle {
|
Ok(StdFileHandle {
|
||||||
id,
|
id,
|
||||||
|
name,
|
||||||
file,
|
file,
|
||||||
start,
|
start,
|
||||||
size,
|
size,
|
||||||
|
@ -85,8 +90,14 @@ impl FileHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn to_std(self, chunk_header: &ChunkHeader) -> Result<StdFileHandle> {
|
async fn to_std(self, chunk_header: &ChunkHeader) -> Result<StdFileHandle> {
|
||||||
println!("{:?} requested start?", chunk_header.start);
|
StdFileHandle::new(
|
||||||
StdFileHandle::new(self.id, self.file, chunk_header.start, self.md.len()).await
|
self.id,
|
||||||
|
pathbuf_to_string(&self.path)?,
|
||||||
|
self.file,
|
||||||
|
chunk_header.start,
|
||||||
|
self.md.len(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_file_offer(&self) -> Result<FileOffer> {
|
pub fn to_file_offer(&self) -> Result<FileOffer> {
|
||||||
|
@ -130,6 +141,6 @@ pub fn pathbuf_to_string(path: &PathBuf) -> Result<String> {
|
||||||
let filename = filename.to_os_string();
|
let filename = filename.to_os_string();
|
||||||
match filename.into_string() {
|
match filename.into_string() {
|
||||||
Ok(s) => Ok(s),
|
Ok(s) => Ok(s),
|
||||||
Err(e) => Err(anyhow!("Error converting {:?} to String", path)),
|
Err(_) => Err(anyhow!("Error converting {:?} to String", path)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl Handshake {
|
||||||
) -> Result<(TcpStream, Vec<u8>)> {
|
) -> Result<(TcpStream, Vec<u8>)> {
|
||||||
let mut socket = socket;
|
let mut socket = socket;
|
||||||
let bytes = &self.to_bytes();
|
let bytes = &self.to_bytes();
|
||||||
println!("client - sending handshake msg= {:?}", &bytes);
|
// println!("client - sending handshake msg= {:?}", &bytes);
|
||||||
socket.write_all(&bytes).await?;
|
socket.write_all(&bytes).await?;
|
||||||
let mut buffer = [0; HANDSHAKE_MSG_SIZE];
|
let mut buffer = [0; HANDSHAKE_MSG_SIZE];
|
||||||
let n = socket.read_exact(&mut buffer).await?;
|
let n = socket.read_exact(&mut buffer).await?;
|
||||||
|
|
Loading…
Reference in a new issue