better error handling
This commit is contained in:
parent
6558e18dec
commit
9fff83a721
3 changed files with 68 additions and 49 deletions
|
@ -128,10 +128,9 @@ impl App {
|
|||
.state
|
||||
.get()
|
||||
.unwrap()
|
||||
.upload_requests
|
||||
.lock()
|
||||
.get_upload_request(id)
|
||||
.await
|
||||
.get(&id).ok_or(LocalSendError::SessionInactive)?.clone();
|
||||
.ok_or(LocalSendError::SessionInactive)?;
|
||||
|
||||
// TODO: replace this with ratatui widget dialog
|
||||
let upload_confirmed = MessageDialogBuilder::default()
|
||||
|
|
23
src/lib.rs
23
src/lib.rs
|
@ -59,7 +59,7 @@ pub struct JoecalState {
|
|||
pub running_state: Arc<Mutex<RunningState>>,
|
||||
pub socket: Arc<UdpSocket>,
|
||||
pub client: reqwest::Client,
|
||||
pub upload_requests: Arc<Mutex<HashMap<Julid, UnboundedSender<UploadDialog>>>>,
|
||||
upload_requests: Arc<Mutex<HashMap<Julid, UnboundedSender<UploadDialog>>>>,
|
||||
shutdown_sender: OnceLock<ShutdownSender>,
|
||||
// the receiving end will be held by the application so it can update the UI based on backend
|
||||
// events
|
||||
|
@ -130,6 +130,9 @@ impl JoecalState {
|
|||
Listeners::Udp
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: add a task that periodically clears out the upload requests if
|
||||
// they're too old; the keys are julids so they have the time in them
|
||||
}
|
||||
|
||||
pub async fn stop(&self) {
|
||||
|
@ -147,6 +150,24 @@ impl JoecalState {
|
|||
let mut peers = self.peers.lock().await;
|
||||
peers.clear();
|
||||
}
|
||||
|
||||
pub async fn get_upload_request(&self, id: Julid) -> Option<UnboundedSender<UploadDialog>> {
|
||||
self.upload_requests.lock().await.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub async fn clear_upload_request(&self, id: Julid) {
|
||||
let _ = self.upload_requests.lock().await.remove(&id);
|
||||
}
|
||||
|
||||
/// Add a transmitter for an upload request confirmation dialog that the
|
||||
/// application frontend can use to tell the Axum handler whether or not to
|
||||
/// accept the upload.
|
||||
///
|
||||
/// IMPORTANT! Be sure to call `clear_upload_request(id)` when you're done
|
||||
/// getting an answer back/before you exit!
|
||||
pub async fn add_upload_request(&self, id: Julid, tx: UnboundedSender<UploadDialog>) {
|
||||
self.upload_requests.lock().await.entry(id).insert_entry(tx);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
|
|
@ -197,12 +197,8 @@ pub async fn register_prepare_upload(
|
|||
|
||||
let id = Julid::new();
|
||||
let (tx, mut rx) = unbounded_channel();
|
||||
state
|
||||
.upload_requests
|
||||
.lock()
|
||||
.await
|
||||
.entry(id)
|
||||
.insert_entry(tx);
|
||||
// be sure to clear this request before this function exits!
|
||||
state.add_upload_request(id, tx).await;
|
||||
|
||||
let dialog_send = state.transfer_event_tx.send(TransferEvent::UploadRequest {
|
||||
alias: req.info.alias.clone(),
|
||||
|
@ -211,52 +207,55 @@ pub async fn register_prepare_upload(
|
|||
match dialog_send {
|
||||
Ok(_) => {}
|
||||
Err(_e) => {
|
||||
let _ = state.upload_requests.lock().await.remove(&id);
|
||||
state.clear_upload_request(id).await;
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
}
|
||||
}
|
||||
|
||||
// safe to unwrap because it's only `None` when there are no more transmitters,
|
||||
// and we still have the `tx` we created earlier
|
||||
let result = rx.recv().await.unwrap();
|
||||
let _ = state.upload_requests.lock().await.remove(&id);
|
||||
let confirmation = rx.recv().await;
|
||||
state.clear_upload_request(id).await;
|
||||
|
||||
if result == UploadDialog::UploadConfirm {
|
||||
let session_id = id.as_string();
|
||||
let Some(confirmation) = confirmation else {
|
||||
// the frontend must have dropped the tx before trying to send a reply back
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
};
|
||||
|
||||
let file_tokens: HashMap<String, String> = req
|
||||
.files
|
||||
.keys()
|
||||
.map(|id| (id.clone(), Julid::new().to_string())) // Replace with actual token logic
|
||||
.collect();
|
||||
|
||||
let session = Session {
|
||||
session_id: session_id.clone(),
|
||||
files: req.files.clone(),
|
||||
file_tokens: file_tokens.clone(),
|
||||
receiver: state.device.clone(),
|
||||
sender: req.info.clone(),
|
||||
status: SessionStatus::Active,
|
||||
addr,
|
||||
};
|
||||
|
||||
state
|
||||
.sessions
|
||||
.lock()
|
||||
.await
|
||||
.insert(session_id.clone(), session);
|
||||
|
||||
(
|
||||
StatusCode::OK,
|
||||
Json(PrepareUploadResponse {
|
||||
session_id,
|
||||
files: file_tokens,
|
||||
}),
|
||||
)
|
||||
.into_response()
|
||||
} else {
|
||||
StatusCode::FORBIDDEN.into_response()
|
||||
if confirmation != UploadDialog::UploadConfirm {
|
||||
return StatusCode::FORBIDDEN.into_response();
|
||||
}
|
||||
|
||||
let session_id = id.as_string();
|
||||
|
||||
let file_tokens: HashMap<String, String> = req
|
||||
.files
|
||||
.keys()
|
||||
.map(|id| (id.clone(), Julid::new().to_string())) // Replace with actual token logic
|
||||
.collect();
|
||||
|
||||
let session = Session {
|
||||
session_id: session_id.clone(),
|
||||
files: req.files.clone(),
|
||||
file_tokens: file_tokens.clone(),
|
||||
receiver: state.device.clone(),
|
||||
sender: req.info.clone(),
|
||||
status: SessionStatus::Active,
|
||||
addr,
|
||||
};
|
||||
|
||||
state
|
||||
.sessions
|
||||
.lock()
|
||||
.await
|
||||
.insert(session_id.clone(), session);
|
||||
|
||||
(
|
||||
StatusCode::OK,
|
||||
Json(PrepareUploadResponse {
|
||||
session_id,
|
||||
files: file_tokens,
|
||||
}),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
pub async fn register_upload(
|
||||
|
|
Loading…
Reference in a new issue