Skip to content

Commit 7a8bf58

Browse files
break out API definitions + use tracing for logging in upload.rs
1 parent a65d871 commit 7a8bf58

File tree

6 files changed

+257
-196
lines changed

6 files changed

+257
-196
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! TODO: We should investigate generating this with OpenAPI.
2+
//! This will come part of the EffectTS rewrite work.
3+
4+
use serde::{Deserialize, Serialize};
5+
use tauri::AppHandle;
6+
7+
use crate::web_api::ManagerExt;
8+
9+
// TODO: Adding retry and backoff logic to everything!
10+
11+
pub async fn upload_multipart_initiate(app: &AppHandle, video_id: &str) -> Result<String, String> {
12+
#[derive(Deserialize)]
13+
pub struct Response {
14+
upload_id: String,
15+
}
16+
17+
let resp = app
18+
.authed_api_request("/api/upload/multipart/initiate", |c, url| {
19+
c.post(url)
20+
.header("Content-Type", "application/json")
21+
.json(&serde_json::json!({
22+
"videoId": video_id,
23+
"contentType": "video/mp4"
24+
}))
25+
})
26+
.await
27+
.map_err(|err| format!("api/upload_multipart_initiate/request: {err}"))?;
28+
29+
if !resp.status().is_success() {
30+
let status = resp.status();
31+
let error_body = resp
32+
.text()
33+
.await
34+
.unwrap_or_else(|_| "<no response body>".to_string());
35+
return Err(format!(
36+
"api/upload_multipart_initiate/{status}: {error_body}"
37+
));
38+
}
39+
40+
resp.json::<Response>()
41+
.await
42+
.map_err(|err| format!("api/upload_multipart_initiate/response: {err}"))
43+
.map(|data| data.upload_id)
44+
}
45+
46+
pub async fn upload_multipart_presign_part(
47+
app: &AppHandle,
48+
video_id: &str,
49+
upload_id: &str,
50+
part_number: u32,
51+
md5_sum: &str,
52+
) -> Result<String, String> {
53+
#[derive(Deserialize)]
54+
#[serde(rename_all = "camelCase")]
55+
pub struct Response {
56+
presigned_url: String,
57+
}
58+
59+
let resp = app
60+
.authed_api_request("/api/upload/multipart/presign-part", |c, url| {
61+
c.post(url)
62+
.header("Content-Type", "application/json")
63+
.json(&serde_json::json!({
64+
"videoId": video_id,
65+
"uploadId": upload_id,
66+
"partNumber": part_number,
67+
"md5Sum": md5_sum
68+
}))
69+
})
70+
.await
71+
.map_err(|err| format!("api/upload_multipart_presign_part/request: {err}"))?;
72+
73+
if !resp.status().is_success() {
74+
let status = resp.status();
75+
let error_body = resp
76+
.text()
77+
.await
78+
.unwrap_or_else(|_| "<no response body>".to_string());
79+
return Err(format!(
80+
"api/upload_multipart_presign_part/{status}: {error_body}"
81+
));
82+
}
83+
84+
resp.json::<Response>()
85+
.await
86+
.map_err(|err| format!("api/upload_multipart_presign_part/response: {err}"))
87+
.map(|data| data.presigned_url)
88+
}
89+
90+
#[derive(Serialize)]
91+
#[serde(rename_all = "camelCase")]
92+
pub struct UploadedPart {
93+
pub part_number: u32,
94+
pub etag: String,
95+
pub size: usize,
96+
}
97+
98+
#[derive(Serialize, Debug, Clone)]
99+
#[serde(rename_all = "camelCase")]
100+
pub struct S3VideoMeta {
101+
#[serde(rename = "durationInSecs")]
102+
pub duration_in_secs: f64,
103+
pub width: u32,
104+
pub height: u32,
105+
#[serde(skip_serializing_if = "Option::is_none")]
106+
pub fps: Option<f32>,
107+
}
108+
109+
pub async fn upload_multipart_complete(
110+
app: &AppHandle,
111+
video_id: &str,
112+
upload_id: &str,
113+
parts: &[UploadedPart],
114+
meta: Option<S3VideoMeta>,
115+
) -> Result<Option<String>, String> {
116+
#[derive(Serialize)]
117+
#[serde(rename_all = "camelCase")]
118+
pub struct MultipartCompleteRequest<'a> {
119+
video_id: &'a str,
120+
upload_id: &'a str,
121+
parts: &'a [UploadedPart],
122+
#[serde(flatten)]
123+
meta: Option<S3VideoMeta>,
124+
}
125+
126+
#[derive(Deserialize)]
127+
pub struct Response {
128+
location: Option<String>,
129+
}
130+
131+
let resp = app
132+
.authed_api_request("/api/upload/multipart/complete", |c, url| {
133+
c.post(url)
134+
.header("Content-Type", "application/json")
135+
.json(&MultipartCompleteRequest {
136+
video_id,
137+
upload_id,
138+
parts,
139+
meta,
140+
})
141+
})
142+
.await
143+
.map_err(|err| format!("api/upload_multipart_complete/request: {err}"))?;
144+
145+
if !resp.status().is_success() {
146+
let status = resp.status();
147+
let error_body = resp
148+
.text()
149+
.await
150+
.unwrap_or_else(|_| "<no response body>".to_string());
151+
return Err(format!(
152+
"api/upload_multipart_complete/{status}: {error_body}"
153+
));
154+
}
155+
156+
resp.json::<Response>()
157+
.await
158+
.map_err(|err| format!("api/upload_multipart_complete/response: {err}"))
159+
.map(|data| data.location)
160+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod api;
12
mod audio;
23
mod audio_meter;
34
mod auth;

0 commit comments

Comments
 (0)