mirror of
https://github.com/Waradu/streamshare.git
synced 2025-04-22 04:14:06 +02:00
added progress indicator
This commit is contained in:
parent
9dcb098754
commit
11264e4be5
4 changed files with 54 additions and 11 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1084,7 +1084,7 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "streamshare"
|
name = "streamshare"
|
||||||
version = "1.1.1"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "streamshare"
|
name = "streamshare"
|
||||||
version = "1.1.1"
|
version = "2.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Upload to streamshare library"
|
description = "Upload to streamshare library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
@ -6,7 +6,8 @@ Upload files to [streamshare](https://streamshare.wireway.ch)
|
||||||
|
|
||||||
Upload:
|
Upload:
|
||||||
```rust
|
```rust
|
||||||
match upload(&file_path).await {
|
let show_progress = true;
|
||||||
|
match upload(&file_path, show_progress).await {
|
||||||
Ok((file_identifier, _deletion_token)) => {
|
Ok((file_identifier, _deletion_token)) => {
|
||||||
let download_url = format!(
|
let download_url = format!(
|
||||||
"https://streamshare.wireway.ch/download/{}",
|
"https://streamshare.wireway.ch/download/{}",
|
||||||
|
|
58
src/lib.rs
58
src/lib.rs
|
@ -1,7 +1,7 @@
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::path::Path;
|
use std::{io::Write, path::Path, time::Instant};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
@ -17,13 +17,14 @@ struct CreateResponse {
|
||||||
deletion_token: String,
|
deletion_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upload(file_path: &str) -> Result<(String, String), Box<dyn std::error::Error>> {
|
pub async fn upload(file_path: &str, show_progress: bool) -> Result<(String, String), Box<dyn std::error::Error>> {
|
||||||
let path = Path::new(file_path);
|
let path = Path::new(file_path);
|
||||||
let metadata = fs::metadata(path).await?;
|
let metadata = fs::metadata(path).await?;
|
||||||
if !metadata.is_file() {
|
if !metadata.is_file() {
|
||||||
return Err("Selected item is not a file".into());
|
return Err("Selected item is not a file".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let file_size = metadata.len();
|
||||||
let file_name = path
|
let file_name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
.and_then(|s| s.to_str())
|
.and_then(|s| s.to_str())
|
||||||
|
@ -43,7 +44,6 @@ pub async fn upload(file_path: &str) -> Result<(String, String), Box<dyn std::er
|
||||||
}
|
}
|
||||||
|
|
||||||
let create_response: CreateResponse = res.json().await?;
|
let create_response: CreateResponse = res.json().await?;
|
||||||
|
|
||||||
let ws_url = format!(
|
let ws_url = format!(
|
||||||
"wss://streamshare.wireway.ch/api/upload/{}",
|
"wss://streamshare.wireway.ch/api/upload/{}",
|
||||||
create_response.file_identifier
|
create_response.file_identifier
|
||||||
|
@ -51,10 +51,10 @@ pub async fn upload(file_path: &str) -> Result<(String, String), Box<dyn std::er
|
||||||
let (mut ws_stream, _) = connect_async(ws_url).await?;
|
let (mut ws_stream, _) = connect_async(ws_url).await?;
|
||||||
|
|
||||||
let mut file = File::open(path).await?;
|
let mut file = File::open(path).await?;
|
||||||
|
const CHUNK_SIZE: usize = 512 * 1024;
|
||||||
const CHUNK_SIZE: usize = 64 * 1024;
|
|
||||||
|
|
||||||
let mut buffer = vec![0u8; CHUNK_SIZE];
|
let mut buffer = vec![0u8; CHUNK_SIZE];
|
||||||
|
let mut uploaded: u64 = 0;
|
||||||
|
let start_time = Instant::now();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let n = file.read(&mut buffer).await?;
|
let n = file.read(&mut buffer).await?;
|
||||||
|
@ -64,8 +64,22 @@ pub async fn upload(file_path: &str) -> Result<(String, String), Box<dyn std::er
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk = &buffer[..n];
|
let chunk = &buffer[..n];
|
||||||
|
|
||||||
ws_stream.send(Message::Binary(chunk.to_vec())).await?;
|
ws_stream.send(Message::Binary(chunk.to_vec())).await?;
|
||||||
|
uploaded += n as u64;
|
||||||
|
|
||||||
|
if show_progress {
|
||||||
|
let percentage = (uploaded as f64 / file_size as f64) * 100.0;
|
||||||
|
let uploaded_mb = bytes_to_human_readable(uploaded);
|
||||||
|
let total_mb = bytes_to_human_readable(file_size);
|
||||||
|
let elapsed_secs = start_time.elapsed().as_secs_f64();
|
||||||
|
let speed = bytes_to_human_readable((uploaded as f64 / elapsed_secs) as u64);
|
||||||
|
|
||||||
|
print!(
|
||||||
|
"\r\x1b[2K{:.2}% {}/{} ({}/s)",
|
||||||
|
percentage, uploaded_mb, total_mb, speed
|
||||||
|
);
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
match ws_stream.next().await {
|
match ws_stream.next().await {
|
||||||
Some(Ok(Message::Text(text))) if text == "ACK" => (),
|
Some(Ok(Message::Text(text))) if text == "ACK" => (),
|
||||||
|
@ -77,6 +91,15 @@ pub async fn upload(file_path: &str) -> Result<(String, String), Box<dyn std::er
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if show_progress {
|
||||||
|
println!(
|
||||||
|
"\r\x1b[2K100.00% {}/{} (Upload complete)",
|
||||||
|
bytes_to_human_readable(file_size),
|
||||||
|
bytes_to_human_readable(file_size)
|
||||||
|
);
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
ws_stream
|
ws_stream
|
||||||
.close(Some(tungstenite::protocol::CloseFrame {
|
.close(Some(tungstenite::protocol::CloseFrame {
|
||||||
code: tungstenite::protocol::frame::coding::CloseCode::Normal,
|
code: tungstenite::protocol::frame::coding::CloseCode::Normal,
|
||||||
|
@ -90,7 +113,10 @@ pub async fn upload(file_path: &str) -> Result<(String, String), Box<dyn std::er
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(file_identifier: &str, deletion_token: &str) -> Result<(), Box<dyn std::error::Error>> {
|
pub async fn delete(
|
||||||
|
file_identifier: &str,
|
||||||
|
deletion_token: &str,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let delete_url = format!(
|
let delete_url = format!(
|
||||||
"https://streamshare.wireway.ch/api/delete/{}/{}",
|
"https://streamshare.wireway.ch/api/delete/{}/{}",
|
||||||
|
@ -104,3 +130,19 @@ pub async fn delete(file_identifier: &str, deletion_token: &str) -> Result<(), B
|
||||||
Err(format!("Failed to delete file: {}", res.status()).into())
|
Err(format!("Failed to delete file: {}", res.status()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bytes_to_human_readable(bytes: u64) -> String {
|
||||||
|
const KB: f64 = 1024.0;
|
||||||
|
const MB: f64 = KB * 1024.0;
|
||||||
|
const GB: f64 = MB * 1024.0;
|
||||||
|
|
||||||
|
if bytes as f64 >= GB {
|
||||||
|
format!("{:.2}gb", bytes as f64 / GB)
|
||||||
|
} else if bytes as f64 >= MB {
|
||||||
|
format!("{:.2}mb", bytes as f64 / MB)
|
||||||
|
} else if bytes as f64 >= KB {
|
||||||
|
format!("{:.2}kb", bytes as f64 / KB)
|
||||||
|
} else {
|
||||||
|
format!("{}b", bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue