fix weird end-of-file bug by having downloaders use inotify to directly track changes
This commit is contained in:
parent
ba4c7bfcbe
commit
cc0aaaab94
8 changed files with 246 additions and 283 deletions
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::HashSet, io::Write, task::Waker};
|
||||
use std::{collections::HashSet, fs::File, io::Write};
|
||||
|
||||
use actix::{fut::future::ActorFutureExt, Actor, ActorContext, AsyncContext, Handler, Message, StreamHandler};
|
||||
use actix::{fut::future::ActorFutureExt, Actor, ActorContext, AsyncContext, StreamHandler};
|
||||
use actix_http::ws::{CloseReason, Item};
|
||||
use actix_web_actors::ws::{self, CloseCode};
|
||||
use bytes::Bytes;
|
||||
|
@ -9,7 +9,7 @@ use rand::distributions::{Alphanumeric, DistString};
|
|||
use serde::Deserialize;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use crate::{file::LiveWriter, DownloadableFile, UploadedFile, storage_dir};
|
||||
use crate::{storage_dir, DownloadableFile, UploadedFile};
|
||||
|
||||
const MAX_FILES: usize = 256;
|
||||
const FILENAME_DATE_FORMAT: &[time::format_description::FormatItem] =
|
||||
|
@ -54,7 +54,7 @@ impl Error {
|
|||
}
|
||||
|
||||
pub struct Uploader {
|
||||
writer: Option<Box<dyn LiveWriter>>,
|
||||
writer: Option<Box<dyn Write>>,
|
||||
storage_filename: String,
|
||||
app_data: super::AppData,
|
||||
bytes_remaining: u64,
|
||||
|
@ -75,21 +75,6 @@ impl Actor for Uploader {
|
|||
type Context = ws::WebsocketContext<Self>;
|
||||
}
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "()")]
|
||||
pub(crate) struct WakerMessage(pub Waker);
|
||||
|
||||
impl Handler<WakerMessage> for Uploader {
|
||||
type Result = ();
|
||||
fn handle(&mut self, msg: WakerMessage, _: &mut Self::Context) {
|
||||
if let Some(w) = self.writer.as_mut() {
|
||||
w.add_waker(msg.0);
|
||||
} else {
|
||||
error!("Got a wakeup request before creating a file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct RawUploadedFile {
|
||||
name: String,
|
||||
|
@ -108,6 +93,15 @@ impl RawUploadedFile {
|
|||
}
|
||||
}
|
||||
|
||||
fn stop_and_flush<T>(_: T, u: &mut Uploader, ctx: &mut <Uploader as Actor>::Context) {
|
||||
ctx.stop();
|
||||
if let Some(w) = u.writer.as_mut() {
|
||||
if let Err(e) = w.flush() {
|
||||
error!("Failed to flush writer: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Uploader {
|
||||
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
||||
let msg = match msg {
|
||||
|
@ -130,17 +124,11 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Uploader {
|
|||
}
|
||||
Ok(true) => {
|
||||
info!("Finished uploading data");
|
||||
self.writer.as_mut().map(|w| w.flush());
|
||||
ctx.close(Some(ws::CloseReason {
|
||||
code: CloseCode::Normal,
|
||||
description: None,
|
||||
}));
|
||||
let data = self.app_data.clone();
|
||||
let filename = self.storage_filename.clone();
|
||||
ctx.wait(actix::fut::wrap_future(async move {
|
||||
debug!("Spawned future to remove uploader from entry {} before stopping", filename);
|
||||
data.write().await.remove_uploader(&filename);
|
||||
}).map(|_, _, ctx: &mut Self::Context| ctx.stop()));
|
||||
stop_and_flush((), self, ctx);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -191,9 +179,11 @@ impl Uploader {
|
|||
self.storage_filename = storage_filename.clone();
|
||||
let storage_path = storage_dir().join(storage_filename.clone());
|
||||
info!("storing to: {:?}", storage_path);
|
||||
let writer = super::file::LiveFileWriter::new(&storage_path)?;
|
||||
let addr = Some(ctx.address());
|
||||
let (writer, downloadable_file): (Box<dyn LiveWriter>, _) = if files.len() > 1 {
|
||||
let writer = File::options()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&storage_path)?;
|
||||
let (writer, downloadable_file): (Box<dyn Write>, _) = if files.len() > 1 {
|
||||
info!("Wrapping in zipfile generator");
|
||||
let now = OffsetDateTime::now_utc();
|
||||
let zip_writer = super::zip::ZipGenerator::new(files, writer);
|
||||
|
@ -206,7 +196,6 @@ impl Uploader {
|
|||
name: download_filename,
|
||||
size,
|
||||
modtime: now,
|
||||
uploader: addr,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -216,7 +205,6 @@ impl Uploader {
|
|||
name: files[0].name.clone(),
|
||||
size: files[0].size,
|
||||
modtime: files[0].modtime,
|
||||
uploader: addr,
|
||||
},
|
||||
)
|
||||
};
|
||||
|
@ -274,13 +262,19 @@ impl Uploader {
|
|||
}
|
||||
|
||||
fn cleanup_after_error(&mut self, ctx: &mut <Self as Actor>::Context) {
|
||||
info!("Cleaning up after failed upload of {}", self.storage_filename);
|
||||
info!(
|
||||
"Cleaning up after failed upload of {}",
|
||||
self.storage_filename
|
||||
);
|
||||
let data = self.app_data.clone();
|
||||
let filename = self.storage_filename.clone();
|
||||
ctx.wait(actix::fut::wrap_future(async move {
|
||||
debug!("Spawned future to remove entry {} from state", filename);
|
||||
data.write().await.remove_file(&filename).await.unwrap();
|
||||
}).map(|_, _, ctx: &mut <Self as Actor>::Context| ctx.stop()));
|
||||
ctx.wait(
|
||||
actix::fut::wrap_future(async move {
|
||||
debug!("Spawned future to remove entry {} from state", filename);
|
||||
data.write().await.remove_file(&filename).await.unwrap();
|
||||
})
|
||||
.map(stop_and_flush),
|
||||
);
|
||||
if let Err(e) = std::fs::remove_file(storage_dir().join(&self.storage_filename)) {
|
||||
error!("Failed to remove file {}: {}", self.storage_filename, e);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue