omni_forge/api/
mod.rs

1use std::fs;
2use std::path::PathBuf;
3use std::str::FromStr;
4use rocket::{get, http::Status, post};
5use rocket::data::Data;
6use rocket::http::ContentType;
7use rocket_multipart_form_data::{MultipartFormData, MultipartFormDataField, MultipartFormDataOptions};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug,Serialize,Deserialize)]
11pub struct DeployPermissions {
12    max_file_count: u64
13}
14impl Default for DeployPermissions {
15    fn default() -> Self {
16        Self { max_file_count: 4500 }
17    }
18}
19#[get("/deploy/permissions")]
20pub fn deploy_permissions() -> Result<rocket::serde::json::Json<DeployPermissions>,Status> {
21
22    Ok(rocket::serde::json::Json(DeployPermissions::default()))
23}
24
25#[post("/app/<app_id>/build", data = "<data>")]
26pub async fn build<'a>(app_id: String, content_type: &ContentType, data: Data<'a>) -> Result<Status,Status> {
27    println!("Starting deploy handler");
28    println!("Content-Type: {:?}", content_type);
29    println!("Build started for app: {:#?}", app_id);
30
31    let mut options = MultipartFormDataOptions::new();
32
33    // Add multiple possible field names to help debug
34    options
35        .allowed_fields
36        .push(MultipartFormDataField::file("media").size_limit(5 * 1024 * 1024 * 1024));
37    options
38        .allowed_fields
39        .push(MultipartFormDataField::file("file").size_limit(5 * 1024 * 1024 * 1024));
40    options
41        .allowed_fields
42        .push(MultipartFormDataField::file("upload").size_limit(5 * 1024 * 1024 * 1024));
43            
44    // Parse form data with detailed error handling
45    let form_data = match MultipartFormData::parse(content_type, data, options).await {
46        Ok(form) => {
47            println!("Successfully parsed form data");
48            form
49        }
50        Err(e) => {
51            println!("Error parsing form data: {:?}", e);
52            return Err(Status::new(400))
53        }
54    };
55
56    // Print ALL available fields for debugging
57    println!("Available fields in form_data:");
58    println!("Raw fields: {:#?}", form_data.raw);
59    println!("Text fields: {:#?}", form_data.texts);
60    println!("Files: {:#?}", form_data.files);
61
62    // Check each possible file field
63    for field_name in ["media", "file", "upload"] {
64        if let Some(files) = form_data.files.get(field_name) {
65            println!("Found files in field '{}': {:?}", field_name, files);
66
67            if let Some(file) = files.first() {
68                println!("Processing file:");
69                println!("    Path: {:?}", file.path);
70                println!("    Filename: {:?}", file.file_name);
71                println!("    Content-Type: {:?}", file.content_type);
72
73                // Create App directory
74                match fs::create_dir_all("./App") {
75                    Ok(_) => {
76                        let dir = std::path::PathBuf::from_str("./App").unwrap();
77                        let canon_dir = dir.canonicalize().unwrap();
78                        log::info!("Created Directory at {}",canon_dir.display())
79                    },
80                    Err(_) => {
81                        return Err::<Status,Status>(Status::new(500));
82                    },
83                }
84                    
85    
86                // Copy file with size verification
87                let source_size = fs::metadata(&file.path)
88                    .map_err(|_| return Err::<Status,Status>(Status::new(500))).unwrap()
89                    .len();
90
91                println!("Source file size: {} bytes", source_size);
92
93                match fs::copy(&file.path, "./App/app.tar.gz") {
94                    Ok(bytes_written) => {
95                        println!("Successfully wrote {} bytes", bytes_written);
96                        if bytes_written == source_size {
97                            let file_path = PathBuf::from_str("./App/app.tar.gz")
98                                .expect("Failed to get app zip");
99                            let tar_gz = fs::File::open(&file_path).expect("Failed to open tar");
100                            let tar = flate2::read::GzDecoder::new(tar_gz);
101                            let mut archive = tar::Archive::new(tar);
102
103                            archive.unpack("./App").unwrap();
104
105                            // Clean up the tar.gz file
106                            fs::remove_file(&file_path).expect("Fail");
107                            return Ok(Status::new(200));
108                                
109                        } else {
110                            return Err(Status::new(500))
111                        }
112                    }
113                    Err(e) => {
114                        println!("Error copying file: {:?}", e);
115                        return Err(Status::new(500))
116                    }
117                }
118            } else {
119                println!("No valid file found in request");
120                return Err(Status::new(500))
121            }
122        }
123    }
124    return Ok::<Status,Status>(Status::new(200));
125}