v0.0.20: file transfer in groups
/file <path> now works in group mode (#group): - Sends file header + chunks to each group member - Same fan-out approach as group text messages - Each member receives and reassembles independently - Progress shown: "Sending 'file.pdf' to group #ops..." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
10
warzone/Cargo.lock
generated
10
warzone/Cargo.lock
generated
@@ -2789,7 +2789,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "warzone-client"
|
||||
version = "0.0.18"
|
||||
version = "0.0.19"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -2822,7 +2822,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "warzone-mule"
|
||||
version = "0.0.18"
|
||||
version = "0.0.19"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2831,7 +2831,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "warzone-protocol"
|
||||
version = "0.0.18"
|
||||
version = "0.0.19"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bincode",
|
||||
@@ -2856,7 +2856,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "warzone-server"
|
||||
version = "0.0.18"
|
||||
version = "0.0.19"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -2883,7 +2883,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "warzone-wasm"
|
||||
version = "0.0.18"
|
||||
version = "0.0.19"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bincode",
|
||||
|
||||
@@ -9,7 +9,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.19"
|
||||
version = "0.0.20"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.75"
|
||||
|
||||
@@ -683,19 +683,82 @@ impl App {
|
||||
let file_id = uuid::Uuid::new_v4().to_string();
|
||||
let total_chunks = ((file_data.len() + CHUNK_SIZE - 1) / CHUNK_SIZE) as u32;
|
||||
|
||||
// Resolve peer
|
||||
// Resolve peer (or group members)
|
||||
let peer = match &self.peer_fp {
|
||||
Some(p) if !p.starts_with('#') => p.clone(),
|
||||
_ => {
|
||||
Some(p) => p.clone(),
|
||||
None => {
|
||||
self.add_message(ChatLine {
|
||||
sender: "system".into(),
|
||||
text: "File transfer requires a DM peer. Use /peer <fingerprint>".into(),
|
||||
text: "Set a peer or group first".into(),
|
||||
is_system: true, is_self: false, message_id: None,
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Group file transfer: send to each member
|
||||
if peer.starts_with('#') {
|
||||
let group_name = &peer[1..];
|
||||
self.add_message(ChatLine {
|
||||
sender: "system".into(),
|
||||
text: format!("Sending '{}' to group #{}...", filename, group_name),
|
||||
is_system: true, is_self: false, message_id: None,
|
||||
});
|
||||
|
||||
// Get members
|
||||
let url = format!("{}/v1/groups/{}", client.base_url, group_name);
|
||||
let group_data = match client.client.get(&url).send().await {
|
||||
Ok(resp) => match resp.json::<serde_json::Value>().await {
|
||||
Ok(d) => d,
|
||||
Err(_) => return,
|
||||
},
|
||||
Err(_) => return,
|
||||
};
|
||||
let my_fp = normfp(&self.our_fp);
|
||||
let members: Vec<String> = group_data.get("members")
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|arr| arr.iter().filter_map(|v| v.as_str().map(String::from)).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
for member in &members {
|
||||
if *member == my_fp { continue; }
|
||||
// Send file header + chunks to each member via HTTP
|
||||
let header = WireMessage::FileHeader {
|
||||
id: file_id.clone(),
|
||||
sender_fingerprint: self.our_fp.clone(),
|
||||
filename: filename.clone(),
|
||||
file_size,
|
||||
total_chunks,
|
||||
sha256: sha256.clone(),
|
||||
};
|
||||
if let Ok(encoded) = bincode::serialize(&header) {
|
||||
let _ = client.send_message(member, Some(&self.our_fp), &encoded).await;
|
||||
}
|
||||
for i in 0..total_chunks {
|
||||
let start = i as usize * CHUNK_SIZE;
|
||||
let end = ((i as usize + 1) * CHUNK_SIZE).min(file_data.len());
|
||||
let chunk_msg = WireMessage::FileChunk {
|
||||
id: file_id.clone(),
|
||||
sender_fingerprint: self.our_fp.clone(),
|
||||
filename: filename.clone(),
|
||||
chunk_index: i,
|
||||
total_chunks,
|
||||
data: file_data[start..end].to_vec(),
|
||||
};
|
||||
if let Ok(encoded) = bincode::serialize(&chunk_msg) {
|
||||
let _ = client.send_message(member, Some(&self.our_fp), &encoded).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.add_message(ChatLine {
|
||||
sender: "system".into(),
|
||||
text: format!("File '{}' sent to group #{}", filename, group_name),
|
||||
is_system: true, is_self: false, message_id: None,
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
let peer_fp = match Fingerprint::from_hex(&peer) {
|
||||
Ok(fp) => fp,
|
||||
Err(_) => {
|
||||
|
||||
Reference in New Issue
Block a user