unnecessary but acceptable changes
the bug was in doppler. oops.
This commit is contained in:
parent
369d0135c3
commit
5fd3188a2c
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1824,6 +1824,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"hyper-rustls 0.27.1",
|
"hyper-rustls 0.27.1",
|
||||||
|
"mime_guess",
|
||||||
"qrencode",
|
"qrencode",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -22,4 +22,5 @@ reqwest = { version = "0.12", default-features = false, features = ["json", "mul
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
sled = "0.34.7"
|
sled = "0.34.7"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
|
mime_guess = "2"
|
68
src/local.rs
68
src/local.rs
|
@ -1,5 +1,6 @@
|
||||||
use std::{os::unix::ffi::OsStrExt, path::Path, sync::Arc};
|
use std::{os::unix::ffi::OsStrExt, path::Path, sync::Arc};
|
||||||
|
|
||||||
|
use mime_guess::Mime;
|
||||||
use reqwest::{multipart, Url};
|
use reqwest::{multipart, Url};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{sync::Semaphore, task::JoinSet};
|
use tokio::{sync::Semaphore, task::JoinSet};
|
||||||
|
@ -77,27 +78,60 @@ impl LocalServer {
|
||||||
base_uri,
|
base_uri,
|
||||||
info,
|
info,
|
||||||
cache,
|
cache,
|
||||||
client: reqwest::Client::new(),
|
client: reqwest::Client::builder()
|
||||||
|
.http1_title_case_headers()
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
tasks: JoinSet::new(),
|
tasks: JoinSet::new(),
|
||||||
semaphore: Arc::new(Semaphore::new(10)),
|
semaphore: Arc::new(Semaphore::new(1)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_upload(&self, path: impl AsRef<Path>) -> bool {
|
fn fuzzy_mime(&self, mime: Mime) -> Option<String> {
|
||||||
|
let mime_str = mime.essence_str();
|
||||||
|
|
||||||
|
if self
|
||||||
|
.info
|
||||||
|
.supported_mimetypes
|
||||||
|
.iter()
|
||||||
|
.any(|mt| mt == mime_str)
|
||||||
|
{
|
||||||
|
Some(mime_str.to_owned())
|
||||||
|
} else {
|
||||||
|
let x_mime = format!("{}/x-{}", mime.type_(), mime.subtype());
|
||||||
|
self.info
|
||||||
|
.supported_mimetypes
|
||||||
|
.iter()
|
||||||
|
.find(|mt| *mt == &x_mime)
|
||||||
|
.map(|_| x_mime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_upload(&self, path: impl AsRef<Path>) -> Option<String> {
|
||||||
|
// We need to confirm a few things:
|
||||||
|
// First, do we have a file extension?
|
||||||
if let Some(extension) = path.as_ref().extension() {
|
if let Some(extension) = path.as_ref().extension() {
|
||||||
let extension = extension.as_bytes();
|
let extension = extension.as_bytes();
|
||||||
|
// Is that file extension in our list of "known" extensions?
|
||||||
if self
|
if self
|
||||||
.info
|
.info
|
||||||
.known_file_extensions
|
.known_file_extensions
|
||||||
.iter()
|
.iter()
|
||||||
.any(|ex| ex.as_bytes() == extension)
|
.any(|ex| ex.as_bytes() == extension)
|
||||||
{
|
{
|
||||||
if let Ok(false) = self.cache.has_path(path.as_ref()) {
|
// We also have to check the mime type...
|
||||||
return true;
|
let mime_type = mime_guess::from_path(&path);
|
||||||
|
if let Some(mime) = mime_type.iter().find(|m| m.type_() == "audio") {
|
||||||
|
// ... is known to the device
|
||||||
|
if let Some(mime) = self.fuzzy_mime(mime) {
|
||||||
|
if let Ok(false) = self.cache.has_path(path.as_ref()) {
|
||||||
|
return Some(mime);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an upload task to the queue. The task will be spawned immediately,
|
/// Adds an upload task to the queue. The task will be spawned immediately,
|
||||||
|
@ -109,12 +143,13 @@ impl LocalServer {
|
||||||
path: impl AsRef<Path>,
|
path: impl AsRef<Path>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
if !self.should_upload(path) {
|
let Some(mime) = self.should_upload(path) else {
|
||||||
return Err(Box::new(std::io::Error::new(
|
return Err(Box::new(std::io::Error::new(
|
||||||
std::io::ErrorKind::InvalidInput,
|
std::io::ErrorKind::InvalidInput,
|
||||||
"Invalid file type",
|
"Invalid file type",
|
||||||
)));
|
)));
|
||||||
}
|
};
|
||||||
|
|
||||||
let filename = path.file_name().unwrap().to_string_lossy().to_string();
|
let filename = path.file_name().unwrap().to_string_lossy().to_string();
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
let base_uri = self.base_uri.clone();
|
let base_uri = self.base_uri.clone();
|
||||||
|
@ -125,21 +160,26 @@ impl LocalServer {
|
||||||
// The actual upload task
|
// The actual upload task
|
||||||
self.tasks.spawn(async move {
|
self.tasks.spawn(async move {
|
||||||
let _permit = semaphore.acquire_owned().await.unwrap();
|
let _permit = semaphore.acquire_owned().await.unwrap();
|
||||||
let fd = tokio::fs::OpenOptions::new()
|
let fd = tokio::fs::OpenOptions::new().read(true).open(&path).await?;
|
||||||
.read(true)
|
|
||||||
.open(path.to_owned())
|
let flen = fd.metadata().await.unwrap().len();
|
||||||
.await?;
|
|
||||||
|
|
||||||
let form = multipart::Form::new()
|
let form = multipart::Form::new()
|
||||||
.part("filename", multipart::Part::text(filename.to_string()))
|
.part("filename", multipart::Part::text(filename.to_string()))
|
||||||
.part("file", multipart::Part::stream(fd).file_name(filename));
|
.part(
|
||||||
|
"file",
|
||||||
|
multipart::Part::stream_with_length(fd, flen)
|
||||||
|
.file_name(filename)
|
||||||
|
.mime_str(mime.as_str())
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
let response = client
|
let response = client
|
||||||
.post(base_uri.join("upload").unwrap())
|
.post(base_uri.join("upload").unwrap())
|
||||||
.multipart(form)
|
.multipart(form)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
response.error_for_status()?;
|
let _bytes = response.bytes().await?;
|
||||||
|
|
||||||
if let Err(err) = cache.store(&path).await {
|
if let Err(err) = cache.store(&path).await {
|
||||||
error!("unable to cache {}: {}", path.display(), err);
|
error!("unable to cache {}: {}", path.display(), err);
|
||||||
|
|
|
@ -109,7 +109,7 @@ async fn sync_dir(dir: impl AsRef<Path>, server: &mut LocalServer) -> bool {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if path.exists() && server.should_upload(&path) {
|
} else if path.exists() && server.should_upload(&path).is_some() {
|
||||||
debug!("Adding {} to queue", path.display());
|
debug!("Adding {} to queue", path.display());
|
||||||
// Add the download to the queue
|
// Add the download to the queue
|
||||||
if let Err(err) = server.queue_upload(&path).await {
|
if let Err(err) = server.queue_upload(&path).await {
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl DopplerWebClient {
|
||||||
&self.code
|
&self.code
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wait_for_device(&mut self, list: &mut DeviceList) -> Result<(String, Uri), Error> {
|
pub async fn wait_for_device(mut self, list: &mut DeviceList) -> Result<(String, Uri), Error> {
|
||||||
let mut device: Option<DevicePayload> = None;
|
let mut device: Option<DevicePayload> = None;
|
||||||
while let Some(msg) = self.ws.next().await {
|
while let Some(msg) = self.ws.next().await {
|
||||||
if let Some(msg) = msg?.as_text() {
|
if let Some(msg) = msg?.as_text() {
|
||||||
|
|
Loading…
Reference in a new issue