@@ -13,28 +13,43 @@ use serde::{Deserialize, Serialize};
1313// Types
1414// =============================================================================
1515
16- /// Response from the pre-sign endpoint
16+ /// Generic API response wrapper
1717#[ derive( Debug , Deserialize ) ]
18+ struct ApiResponse < T > {
19+ success : bool ,
20+ data : Option < T > ,
21+ error : Option < String > ,
22+ }
23+
24+ /// Data from the pre-sign endpoint
25+ #[ derive( Debug , Deserialize ) ]
26+ struct PresignData {
27+ upload_url : String ,
28+ job_id : String ,
29+ }
30+
31+ /// Public presign response (flattened for caller convenience)
32+ #[ derive( Debug ) ]
1833pub struct PresignResponse {
19- /// Pre-signed upload URL
2034 pub upload_url : String ,
21- /// Job ID for tracking
2235 pub job_id : String ,
23- /// File key in storage
24- pub file_key : String ,
2536}
2637
27- /// Request to create a job
38+ /// Request to complete upload
2839#[ derive( Debug , Serialize ) ]
29- struct CreateJobRequest {
30- file_key : String ,
31- source : String ,
32- chat_count : usize ,
33- message_count : usize ,
40+ struct CompleteUploadRequest {
41+ job_id : String ,
3442}
3543
36- /// Response from the create job endpoint
44+ /// Data from the complete endpoint
3745#[ derive( Debug , Deserialize ) ]
46+ struct CompleteData {
47+ job_id : String ,
48+ status : String ,
49+ }
50+
51+ /// Public complete response
52+ #[ derive( Debug ) ]
3853pub struct CreateJobResponse {
3954 pub job_id : String ,
4055 pub status : String ,
@@ -61,11 +76,12 @@ pub const SERVER_BASE_URL: &str = "https://chattomap.com";
6176/// Request a pre-signed upload URL from the server
6277pub async fn get_presigned_url ( ) -> Result < PresignResponse , String > {
6378 let client = Client :: new ( ) ;
64- let url = format ! ( "{}/api/desktop /presign" , SERVER_BASE_URL ) ;
79+ let url = format ! ( "{}/api/upload /presign" , SERVER_BASE_URL ) ;
6580
6681 let response = client
6782 . post ( & url)
6883 . header ( "Content-Type" , "application/json" )
84+ . body ( "{}" )
6985 . send ( )
7086 . await
7187 . map_err ( |e| format ! ( "Failed to request presigned URL: {e}" ) ) ?;
@@ -80,10 +96,25 @@ pub async fn get_presigned_url() -> Result<PresignResponse, String> {
8096 ) ) ;
8197 }
8298
83- response
84- . json :: < PresignResponse > ( )
99+ let api_response : ApiResponse < PresignData > = response
100+ . json ( )
85101 . await
86- . map_err ( |e| format ! ( "Failed to parse presign response: {e}" ) )
102+ . map_err ( |e| format ! ( "Failed to parse presign response: {e}" ) ) ?;
103+
104+ if !api_response. success {
105+ return Err ( api_response
106+ . error
107+ . unwrap_or_else ( || "Unknown error" . to_string ( ) ) ) ;
108+ }
109+
110+ let data = api_response
111+ . data
112+ . ok_or ( "Missing data in presign response" ) ?;
113+
114+ Ok ( PresignResponse {
115+ upload_url : data. upload_url ,
116+ job_id : data. job_id ,
117+ } )
87118}
88119
89120/// Upload a file to the pre-signed URL
@@ -135,43 +166,51 @@ pub async fn upload_file(
135166 Ok ( ( ) )
136167}
137168
138- /// Notify server that upload is complete and create processing job
139- pub async fn create_job (
140- file_key : & str ,
141- chat_count : usize ,
142- message_count : usize ,
143- ) -> Result < CreateJobResponse , String > {
169+ /// Notify server that upload is complete and start processing
170+ pub async fn complete_upload ( job_id : & str ) -> Result < CreateJobResponse , String > {
144171 let client = Client :: new ( ) ;
145- let url = format ! ( "{}/api/desktop/job " , SERVER_BASE_URL ) ;
172+ let url = format ! ( "{}/api/upload/complete " , SERVER_BASE_URL ) ;
146173
147- let request = CreateJobRequest {
148- file_key : file_key. to_string ( ) ,
149- source : "imessage" . to_string ( ) ,
150- chat_count,
151- message_count,
174+ let request = CompleteUploadRequest {
175+ job_id : job_id. to_string ( ) ,
152176 } ;
153177
154178 let response = client
155179 . post ( & url)
156180 . json ( & request)
157181 . send ( )
158182 . await
159- . map_err ( |e| format ! ( "Failed to create job : {e}" ) ) ?;
183+ . map_err ( |e| format ! ( "Failed to complete upload : {e}" ) ) ?;
160184
161185 if !response. status ( ) . is_success ( ) {
162186 let status = response. status ( ) ;
163187 let body = response. text ( ) . await . unwrap_or_default ( ) ;
164188 return Err ( format ! (
165- "Create job failed {}: {}" ,
189+ "Complete upload failed {}: {}" ,
166190 status,
167191 sanitize_error_body( & body)
168192 ) ) ;
169193 }
170194
171- response
172- . json :: < CreateJobResponse > ( )
195+ let api_response : ApiResponse < CompleteData > = response
196+ . json ( )
173197 . await
174- . map_err ( |e| format ! ( "Failed to parse job response: {e}" ) )
198+ . map_err ( |e| format ! ( "Failed to parse complete response: {e}" ) ) ?;
199+
200+ if !api_response. success {
201+ return Err ( api_response
202+ . error
203+ . unwrap_or_else ( || "Unknown error" . to_string ( ) ) ) ;
204+ }
205+
206+ let data = api_response
207+ . data
208+ . ok_or ( "Missing data in complete response" ) ?;
209+
210+ Ok ( CreateJobResponse {
211+ job_id : data. job_id ,
212+ status : data. status ,
213+ } )
175214}
176215
177216/// Get the results page URL for a job
0 commit comments