Skip to content

Commit 52fc85d

Browse files
fix error handling
1 parent ebf3714 commit 52fc85d

12 files changed

Lines changed: 131 additions & 63 deletions

File tree

apps/desktop/src-tauri/src/api.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,12 @@ pub async fn upload_multipart_initiate(
3535
.text()
3636
.await
3737
.unwrap_or_else(|_| "<no response body>".to_string());
38-
return Err(format!(
39-
"api/upload_multipart_initiate/{status}: {error_body}"
40-
));
38+
return Err(format!("api/upload_multipart_initiate/{status}: {error_body}").into());
4139
}
4240

4341
resp.json::<Response>()
4442
.await
45-
.map_err(|err| format!("api/upload_multipart_initiate/response: {err}"))
43+
.map_err(|err| format!("api/upload_multipart_initiate/response: {err}").into())
4644
.map(|data| data.upload_id)
4745
}
4846

@@ -79,14 +77,12 @@ pub async fn upload_multipart_presign_part(
7977
.text()
8078
.await
8179
.unwrap_or_else(|_| "<no response body>".to_string());
82-
return Err(format!(
83-
"api/upload_multipart_presign_part/{status}: {error_body}"
84-
));
80+
return Err(format!("api/upload_multipart_presign_part/{status}: {error_body}").into());
8581
}
8682

8783
resp.json::<Response>()
8884
.await
89-
.map_err(|err| format!("api/upload_multipart_presign_part/response: {err}"))
85+
.map_err(|err| format!("api/upload_multipart_presign_part/response: {err}").into())
9086
.map(|data| data.presigned_url)
9187
}
9288

@@ -153,14 +149,12 @@ pub async fn upload_multipart_complete(
153149
.text()
154150
.await
155151
.unwrap_or_else(|_| "<no response body>".to_string());
156-
return Err(format!(
157-
"api/upload_multipart_complete/{status}: {error_body}"
158-
));
152+
return Err(format!("api/upload_multipart_complete/{status}: {error_body}").into());
159153
}
160154

161155
resp.json::<Response>()
162156
.await
163-
.map_err(|err| format!("api/upload_multipart_complete/response: {err}"))
157+
.map_err(|err| format!("api/upload_multipart_complete/response: {err}").into())
164158
.map(|data| data.location)
165159
}
166160

@@ -210,12 +204,12 @@ pub async fn upload_signed(
210204
.text()
211205
.await
212206
.unwrap_or_else(|_| "<no response body>".to_string());
213-
return Err(format!("api/upload_signed/{status}: {error_body}"));
207+
return Err(format!("api/upload_signed/{status}: {error_body}").into());
214208
}
215209

216210
resp.json::<Response>()
217211
.await
218-
.map_err(|err| format!("api/upload_signed/response: {err}"))
212+
.map_err(|err| format!("api/upload_signed/response: {err}").into())
219213
.map(|data| data.presigned_put_data.url)
220214
}
221215

@@ -243,7 +237,7 @@ pub async fn desktop_video_progress(
243237
.text()
244238
.await
245239
.unwrap_or_else(|_| "<no response body>".to_string());
246-
return Err(format!("api/desktop_video_progress/{status}: {error_body}"));
240+
return Err(format!("api/desktop_video_progress/{status}: {error_body}").into());
247241
}
248242

249243
Ok(())

apps/desktop/src-tauri/src/deeplink_actions.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ impl DeepLinkAction {
138138
mode,
139139
};
140140

141-
crate::recording::start_recording(app.clone(), state, inputs).await
141+
crate::recording::start_recording(app.clone(), state, inputs)
142+
.await
143+
.map(|_| ())
142144
}
143145
DeepLinkAction::StopRecording => {
144146
crate::recording::stop_recording(app.clone(), app.state()).await

apps/desktop/src-tauri/src/hotkeys.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ async fn handle_hotkey(app: AppHandle, action: HotkeyAction) -> Result<(), Strin
146146
Ok(())
147147
}
148148
HotkeyAction::StopRecording => recording::stop_recording(app.clone(), app.state()).await,
149-
HotkeyAction::RestartRecording => {
150-
recording::restart_recording(app.clone(), app.state()).await
151-
}
149+
HotkeyAction::RestartRecording => recording::restart_recording(app.clone(), app.state())
150+
.await
151+
.map(|_| ()),
152152
HotkeyAction::OpenRecordingPicker => {
153153
let _ = RequestOpenRecordingPicker { target_mode: None }.emit(&app);
154154
Ok(())

apps/desktop/src-tauri/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ use tauri_specta::Event;
8686
use tokio::sync::Mutex;
8787
use tokio::sync::{RwLock, oneshot};
8888
use tracing::{error, trace, warn};
89-
use upload::{S3UploadMeta, create_or_get_video, upload_image, upload_video};
89+
use upload::{create_or_get_video, upload_image, upload_video};
9090
use web_api::AuthedApiError;
9191
use web_api::ManagerExt as WebManagerExt;
9292
use windows::{CapWindowId, EditorWindowIds, ShowCapWindow, set_window_transparent};
@@ -1167,7 +1167,9 @@ async fn upload_exported_video(
11671167

11681168
NotificationType::UploadFailed.send(&app);
11691169

1170-
meta.upload = Some(UploadMeta::Failed { error: e.to_string() });
1170+
meta.upload = Some(UploadMeta::Failed {
1171+
error: e.to_string(),
1172+
});
11711173
meta.save_for_project()
11721174
.map_err(|e| error!("Failed to save recording meta: {e}"))
11731175
.ok();
@@ -2549,7 +2551,7 @@ async fn resume_uploads(app: AppHandle) -> Result<(), String> {
25492551
error!("Error completing resumed upload for video: {error}");
25502552

25512553
if let Ok(mut meta) = RecordingMeta::load_for_project(&recording_dir).map_err(|err| error!("Error loading project metadata: {err}")) {
2552-
meta.upload = Some(UploadMeta::Failed { error });
2554+
meta.upload = Some(UploadMeta::Failed { error: error.to_string() });
25532555
meta.save_for_project().map_err(|err| error!("Error saving project metadata: {err}")).ok();
25542556
}
25552557
})

apps/desktop/src-tauri/src/recording.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,21 @@ pub enum RecordingEvent {
246246
Failed { error: String },
247247
}
248248

249+
#[derive(Serialize, Type)]
250+
pub enum RecordingAction {
251+
Started,
252+
InvalidAuthentication,
253+
UpgradeRequired,
254+
}
255+
249256
#[tauri::command]
250257
#[specta::specta]
251258
#[tracing::instrument(name = "recording", skip_all)]
252259
pub async fn start_recording(
253260
app: AppHandle,
254261
state_mtx: MutableState<'_, App>,
255262
inputs: StartRecordingInputs,
256-
) -> Result<(), AuthedApiError> {
263+
) -> Result<RecordingAction, String> {
257264
if !matches!(state_mtx.read().await.recording_state, RecordingState::None) {
258265
return Err("Recording already in progress".to_string());
259266
}
@@ -295,7 +302,7 @@ pub async fn start_recording(
295302
match AuthStore::get(&app).ok().flatten() {
296303
Some(_) => {
297304
// Pre-create the video and get the shareable link
298-
let s3_config = create_or_get_video(
305+
let s3_config = match create_or_get_video(
299306
&app,
300307
false,
301308
None,
@@ -306,10 +313,19 @@ pub async fn start_recording(
306313
None,
307314
)
308315
.await
309-
.map_err(|err| {
310-
error!("Error creating instant mode video: {err}");
311-
err
312-
})?;
316+
{
317+
Ok(meta) => meta,
318+
Err(AuthedApiError::InvalidAuthentication) => {
319+
return Ok(RecordingAction::InvalidAuthentication);
320+
}
321+
Err(AuthedApiError::UpgradeRequired) => {
322+
return Ok(RecordingAction::UpgradeRequired);
323+
}
324+
Err(err) => {
325+
error!("Error creating instant mode video: {err}");
326+
return Err(err.to_string());
327+
}
328+
};
313329

314330
let link = app.make_app_url(format!("/s/{}", s3_config.id)).await;
315331
info!("Pre-created shareable link: {}", link);
@@ -619,7 +635,7 @@ pub async fn start_recording(
619635

620636
AppSounds::StartRecording.play();
621637

622-
Ok(())
638+
Ok(RecordingAction::Started)
623639
}
624640

625641
#[tauri::command]
@@ -664,7 +680,10 @@ pub async fn stop_recording(app: AppHandle, state: MutableState<'_, App>) -> Res
664680

665681
#[tauri::command]
666682
#[specta::specta]
667-
pub async fn restart_recording(app: AppHandle, state: MutableState<'_, App>) -> Result<(), String> {
683+
pub async fn restart_recording(
684+
app: AppHandle,
685+
state: MutableState<'_, App>,
686+
) -> Result<RecordingAction, String> {
668687
let Some(recording) = state.write().await.clear_current_recording() else {
669688
return Err("No recording in progress".to_string());
670689
};
@@ -878,7 +897,7 @@ async fn handle_recording_finish(
878897
.handle
879898
.await
880899
.map_err(|e| e.to_string())
881-
.and_then(|r| r)
900+
.and_then(|r| r.map_err(|v| v.to_string()))
882901
{
883902
Ok(()) => {
884903
info!(
@@ -936,7 +955,9 @@ async fn handle_recording_finish(
936955
error!("Error in upload_video: {error}");
937956

938957
if let Ok(mut meta) = RecordingMeta::load_for_project(&recording_dir) {
939-
meta.upload = Some(UploadMeta::Failed { error });
958+
meta.upload = Some(UploadMeta::Failed {
959+
error: error.to_string(),
960+
});
940961
meta.save_for_project()
941962
.map_err(|e| format!("Failed to save recording meta: {e}"))
942963
.ok();

apps/desktop/src-tauri/src/upload.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
api::{self, PresignedS3PutRequest, PresignedS3PutRequestMethod, S3VideoMeta, UploadedPart},
66
general_settings::GeneralSettingsStore,
77
upload_legacy,
8-
web_api::ManagerExt,
8+
web_api::{AuthedApiError, ManagerExt},
99
};
1010
use async_stream::{stream, try_stream};
1111
use axum::http::Uri;
@@ -17,6 +17,7 @@ use flume::Receiver;
1717
use futures::{Stream, StreamExt, TryStreamExt, stream};
1818
use image::{ImageReader, codecs::jpeg::JpegEncoder};
1919
use reqwest::StatusCode;
20+
use sentry::types::Auth;
2021
use serde::{Deserialize, Serialize};
2122
use specta::Type;
2223
use std::{
@@ -129,7 +130,7 @@ pub async fn upload_video(
129130
stream::once(async move { Ok::<_, std::io::Error>(bytes::Bytes::from(bytes)) }),
130131
);
131132

132-
let (video_result, thumbnail_result): (Result<_, String>, Result<_, String>) =
133+
let (video_result, thumbnail_result): (Result<_, AuthedApiError>, Result<_, AuthedApiError>) =
133134
tokio::join!(video_fut, thumbnail_fut);
134135

135136
let _ = (video_result?, thumbnail_result?);
@@ -154,7 +155,10 @@ async fn file_reader_stream(path: impl AsRef<Path>) -> Result<(ReaderStream<File
154155
Ok((ReaderStream::new(file), metadata.len()))
155156
}
156157

157-
pub async fn upload_image(app: &AppHandle, file_path: PathBuf) -> Result<UploadedItem, String> {
158+
pub async fn upload_image(
159+
app: &AppHandle,
160+
file_path: PathBuf,
161+
) -> Result<UploadedItem, AuthedApiError> {
158162
let is_new_uploader_enabled = GeneralSettingsStore::get(app)
159163
.map_err(|err| error!("Error checking status of new uploader flow from settings: {err}"))
160164
.ok()
@@ -167,7 +171,8 @@ pub async fn upload_image(app: &AppHandle, file_path: PathBuf) -> Result<Uploade
167171
.map(|v| UploadedItem {
168172
link: v.link,
169173
id: v.id,
170-
});
174+
})
175+
.map_err(Into::into);
171176
}
172177

173178
let file_name = file_path
@@ -205,7 +210,7 @@ pub async fn create_or_get_video(
205210
name: Option<String>,
206211
meta: Option<S3VideoMeta>,
207212
) -> Result<S3UploadMeta, AuthedApiError> {
208-
return Err(AuthedApiError::InvalidAuthentication); // TODO
213+
return Err(AuthedApiError::Other("A made up error".into())); // TODO
209214

210215
let mut s3_config_url = if let Some(id) = video_id {
211216
format!("/api/desktop/video/create?recordingMode=desktopMP4&videoId={id}")
@@ -315,7 +320,7 @@ pub async fn compress_image(path: PathBuf) -> Result<Vec<u8>, String> {
315320
}
316321

317322
pub struct InstantMultipartUpload {
318-
pub handle: tokio::task::JoinHandle<Result<(), String>>,
323+
pub handle: tokio::task::JoinHandle<Result<(), AuthedApiError>>,
319324
}
320325

321326
impl InstantMultipartUpload {
@@ -345,7 +350,7 @@ impl InstantMultipartUpload {
345350
pre_created_video: VideoUploadInfo,
346351
realtime_video_done: Option<Receiver<()>>,
347352
recording_dir: PathBuf,
348-
) -> Result<(), String> {
353+
) -> Result<(), AuthedApiError> {
349354
let is_new_uploader_enabled = GeneralSettingsStore::get(&app)
350355
.map_err(|err| {
351356
error!("Error checking status of new uploader flow from settings: {err}")
@@ -362,7 +367,8 @@ impl InstantMultipartUpload {
362367
pre_created_video,
363368
realtime_video_done,
364369
)
365-
.await;
370+
.await
371+
.map_err(Into::into);
366372
}
367373

368374
let video_id = pre_created_video.id.clone();
@@ -594,7 +600,7 @@ fn multipart_uploader(
594600
video_id: String,
595601
upload_id: String,
596602
stream: impl Stream<Item = io::Result<Chunk>>,
597-
) -> impl Stream<Item = Result<UploadedPart, String>> {
603+
) -> impl Stream<Item = Result<UploadedPart, AuthedApiError>> {
598604
debug!("Initializing multipart uploader for video {video_id:?}");
599605

600606
try_stream! {
@@ -647,7 +653,7 @@ pub async fn singlepart_uploader(
647653
request: PresignedS3PutRequest,
648654
total_size: u64,
649655
stream: impl Stream<Item = io::Result<Bytes>> + Send + 'static,
650-
) -> Result<(), String> {
656+
) -> Result<(), AuthedApiError> {
651657
let presigned_url = api::upload_signed(&app, request).await?;
652658

653659
let url = Uri::from_str(&presigned_url)

apps/desktop/src-tauri/src/web_api.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use reqwest::StatusCode;
2+
use serde::Serialize;
3+
use specta::Type;
24
use tauri::{Emitter, Manager, Runtime};
35
use tauri_specta::Event;
46
use thiserror::Error;

apps/desktop/src/routes/(window-chrome)/(main).tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,16 +238,14 @@ function Page() {
238238
}
239239
})();
240240

241-
try {
242-
await commands.startRecording({
241+
await handleRecordingResult(
242+
commands.startRecording({
243243
capture_target,
244244
mode: payload.mode,
245245
capture_system_audio: rawOptions.captureSystemAudio,
246-
});
247-
} catch (err) {
248-
alert("CRINGE");
249-
throw err;
250-
}
246+
}),
247+
setOptions,
248+
);
251249
} else await commands.stopRecording();
252250
},
253251
}));
@@ -600,6 +598,7 @@ import {
600598
RecordingOptionsProvider,
601599
useRecordingOptions,
602600
} from "./OptionsContext";
601+
import { handleRecordingResult } from "~/utils/recording";
603602

604603
let hasChecked = false;
605604
function createUpdateCheck() {

apps/desktop/src/routes/in-progress-recording.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import {
1919
createCurrentRecordingQuery,
2020
createOptionsQuery,
2121
} from "~/utils/queries";
22+
import { handleRecordingResult } from "~/utils/recording";
2223
import { commands, events } from "~/utils/tauri";
24+
import { useRecordingOptions } from "./(window-chrome)/OptionsContext";
2325

2426
type State =
2527
| { variant: "countdown"; from: number; current: number }
@@ -48,6 +50,7 @@ export default function () {
4850
const [start, setStart] = createSignal(Date.now());
4951
const [time, setTime] = createSignal(Date.now());
5052
const currentRecording = createCurrentRecordingQuery();
53+
const { setOptions } = useRecordingOptions();
5154
const optionsQuery = createOptionsQuery();
5255
const auth = authStore.createQuery();
5356

@@ -128,7 +131,7 @@ export default function () {
128131

129132
if (!shouldRestart) return;
130133

131-
await commands.restartRecording();
134+
await handleRecordingResult(commands.restartRecording(), setOptions);
132135

133136
setState({ variant: "recording" });
134137
setTime(Date.now());

0 commit comments

Comments
 (0)