phemios_core/
network_export.rs1use super::*;
3impl Client {
4 pub fn export_original(
6 &self,
7 reference: &str,
8 stamp: &str,
9 expected: u64,
10 path: &std::path::Path,
11 valid: &dyn Fn() -> Result<(), String>,
12 progress: &dyn Fn(u64),
13 ) -> Result<(), String> {
14 use std::io::{Read, Write};
15 if !reference.starts_with("track:")
16 || reference.len() > 4096
17 || stamp.len() > 128
18 || expected == 0
19 || expected > 64 * 1024 * 1024 * 1024
20 {
21 return Err("Original audio invalide ou trop volumineux.".into());
22 }
23 valid()?;
24 self.require_unrestricted_download_admitted(valid)?;
25 let mut response = self
26 .agent
27 .get(format!("{}/api/me/v1/exports/original", self.server))
28 .header("Authorization", format!("Bearer {}", self.token))
29 .header("Accept-Encoding", "identity")
30 .query("ref", reference)
31 .query("stamp", stamp)
32 .config()
33 .timeout_global(Some(std::time::Duration::from_secs(3600)))
34 .timeout_resolve(Some(std::time::Duration::from_secs(15)))
35 .timeout_connect(Some(std::time::Duration::from_secs(15)))
36 .timeout_send_request(Some(std::time::Duration::from_secs(15)))
39 .timeout_recv_response(None)
40 .timeout_recv_body(Some(std::time::Duration::from_secs(15)))
41 .build()
42 .call()
43 .map_err(|_| "Téléchargement de l’original interrompu.")?;
44 if response.status() != ureq::http::StatusCode::OK
45 || response
46 .headers()
47 .get("content-length")
48 .and_then(|v| v.to_str().ok())
49 .and_then(|v| v.parse::<u64>().ok())
50 != Some(expected)
51 || response
52 .headers()
53 .get("content-encoding")
54 .is_some_and(|v| v != "identity")
55 {
56 return Err("Original indisponible, modifié ou export non autorisé. Actualisez Aède et réessayez.".into());
57 }
58 let mut options = std::fs::OpenOptions::new();
59 options.write(true).create_new(true);
60 #[cfg(unix)]
61 {
62 use std::os::unix::fs::OpenOptionsExt;
63 options.mode(0o600);
64 }
65 let mut file = options
66 .open(path)
67 .map_err(|_| "Fichier temporaire indisponible.")?;
68 let mut reader = response.body_mut().as_reader();
69 let mut buffer = vec![0; 64 * 1024];
70 let mut count = 0u64;
71 loop {
72 valid()?;
73 let n = reader
74 .read(&mut buffer)
75 .map_err(|_| "Téléchargement de l’original interrompu.")?;
76 if n == 0 {
77 break;
78 }
79 count = count
80 .checked_add(n as u64)
81 .ok_or("Original trop volumineux.")?;
82 if count > expected {
83 return Err("L’original dépasse sa taille annoncée.".into());
84 }
85 file.write_all(&buffer[..n])
86 .map_err(|_| "Espace temporaire insuffisant ou écriture impossible.")?;
87 progress(count);
88 }
89 if count != expected {
90 return Err("L’original téléchargé est incomplet.".into());
91 }
92 file.sync_all()
93 .map_err(|_| "Écriture temporaire impossible.")?;
94 valid()
95 }
96}
97#[cfg(test)]
98#[path = "network_export_tests.rs"]
99mod tests;