1use crate::models::app::{App, AppWithInstanceCount, AppWithInstances};
14use crate::models::instance::Instance;
15use super::super::db::queries as db;
16use rocket::http::Status;
17use rocket::serde::json::{json, Json, Value};
18use rocket::{delete, get, http::ContentType, post, put, Data, State};
19use serde::{Deserialize, Serialize};
20use sqlx::MySql;
21use std::collections::HashMap;
22use std::sync::Arc;
23use tokio::sync::RwLock;
24use anyhow::Error;
25
26use crate::DatabaseManager;
28
29#[derive(Debug, Serialize, Deserialize, Clone)]
33pub struct Application {
34 id: String,
36 name: String,
38 owner: String,
40 instances: i64,
42 memory: i64,
44 status: String,
46 created_at: chrono::DateTime<chrono::Utc>,
48 updated_at: chrono::DateTime<chrono::Utc>,
50}
51
52#[derive(Debug, Serialize, Deserialize)]
54pub struct ScaleRequest {
55 instances: i32,
57 memory: i32,
59}
60
61#[derive(Debug, Serialize, Deserialize)]
63pub struct AppStats {
64 cpu_usage: f64,
66 memory_usage: i64,
68 disk_usage: i64,
70 requests_per_second: f64,
72 response_time_ms: i64,
74}
75
76#[derive(Debug, Serialize, Deserialize)]
78pub struct CreateAppRequest {
79 name: String,
81 memory: i64,
83 instances: i64,
85 org_id: i64,
87}
88
89#[derive(Debug, Serialize, Deserialize)]
91pub struct UpdateAppRequest {
92 name: String,
94 memory: i64,
96 instances: i64,
98 org_id: i64,
100}
101
102#[get("/platform/<platform_id>/apps?<page>&<per_page>")]
115pub async fn list_apps(
116 platform_id: i64,
117 page: Option<i64>,
118 per_page: Option<i64>,
119 db_manager: &State<Arc<DatabaseManager>>,
120) -> Result<Json<Value>, (Status, Json<Value>)> {
121 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
123 Ok(platform) => platform,
124 Err(_) => {
125 return Err((
126 Status::NotFound,
127 Json(json!({
128 "error": "Platform not found",
129 "message": format!("Platform with ID {} does not exist", platform_id)
130 }))
131 ));
132 }
133 };
134
135 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
137 Ok(pool) => pool,
138 Err(_) => {
139 return Err((
140 Status::InternalServerError,
141 Json(json!({
142 "error": "Database error",
143 "message": "Failed to connect to platform database"
144 }))
145 ));
146 }
147 };
148
149 match (page, per_page) {
150 (Some(p), Some(pp)) => {
151 let apps = match db::app::list_apps(&pool, p, pp).await {
152 Ok(apps) => apps,
153 Err(_) => {
154 return Err((
155 Status::InternalServerError,
156 Json(json!({
157 "error": "Database error",
158 "message": "Failed to retrieve applications"
159 }))
160 ));
161 }
162 };
163
164 let total_count = match db::app::count_apps(&pool).await {
165 Ok(count) => count,
166 Err(_) => {
167 return Err((
168 Status::InternalServerError,
169 Json(json!({
170 "error": "Database error",
171 "message": "Failed to count applications"
172 }))
173 ));
174 }
175 };
176
177 let total_pages = (total_count / pp);
178
179 let response = json!({
180 "apps": apps,
181 "pagination": {
182 "page": p,
183 "per_page": pp,
184 "total_count": total_count,
185 "total_pages": total_pages
186 }
187 });
188
189 Ok(Json(response))
190 }
191 _ => Err((
192 Status::BadRequest,
193 Json(json!({
194 "error": "Missing pagination parameters",
195 "message": "Please provide both 'page' and 'per_page' parameters"
196 }))
197 ))
198 }
199}
200
201#[get("/platform/<platform_id>/app_with_instances/<app_id>")]
203pub async fn get_app_with_instances(
204 db_manager: &State<Arc<DatabaseManager>>,
205 platform_id: i64,
206 app_id: i64
207) -> Result<Json<AppWithInstances>, (Status, Json<Value>)> {
208 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
210 Ok(platform) => platform,
211 Err(_) => {
212 return Err((
213 Status::NotFound,
214 Json(json!({
215 "error": "Platform not found",
216 "message": format!("Platform with ID {} does not exist", platform_id)
217 }))
218 ));
219 }
220 };
221
222 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
224 Ok(pool) => pool,
225 Err(_) => {
226 return Err((
227 Status::InternalServerError,
228 Json(json!({
229 "error": "Database error",
230 "message": "Failed to connect to platform database"
231 }))
232 ));
233 }
234 };
235
236 match db::app::get_app_with_instances(&pool, app_id).await {
237 Ok(app_with_instances) => {
238 Ok(Json(app_with_instances))
239 }
240 Err(_) => Err((
241 Status::InternalServerError,
242 Json(json!({
243 "error": "Failed to fetch app with instances",
244 "message": "An error occurred while retrieving the application data"
245 })),
246 )),
247 }
248}
249
250#[get("/platform/<platform_id>/app-count")]
252pub async fn count_apps(
253 platform_id: i64,
254 db_manager: &State<Arc<DatabaseManager>>
255) -> Result<Json<i64>, (Status, Json<Value>)> {
256 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
258 Ok(platform) => platform,
259 Err(_) => {
260 return Err((
261 Status::NotFound,
262 Json(json!({
263 "error": "Platform not found",
264 "message": format!("Platform with ID {} does not exist", platform_id)
265 }))
266 ));
267 }
268 };
269
270 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
272 Ok(pool) => pool,
273 Err(_) => {
274 return Err((
275 Status::InternalServerError,
276 Json(json!({
277 "error": "Database error",
278 "message": "Failed to connect to platform database"
279 }))
280 ));
281 }
282 };
283
284 match db::app::count_apps(&pool).await {
285 Ok(count) => Ok(Json(count)),
286 Err(_) => Err((
287 Status::InternalServerError,
288 Json(json!({
289 "error": "Database error",
290 "message": "Failed to count applications"
291 }))
292 )),
293 }
294}
295
296#[get("/platform/<platform_id>/apps/<app_id>")]
308pub async fn get_app(
309 platform_id: i64,
310 app_id: i64,
311 db_manager: &State<Arc<DatabaseManager>>
312) -> Result<Json<App>, (Status, Json<Value>)> {
313 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
315 Ok(platform) => platform,
316 Err(_) => {
317 return Err((
318 Status::NotFound,
319 Json(json!({
320 "error": "Platform not found",
321 "message": format!("Platform with ID {} does not exist", platform_id)
322 }))
323 ));
324 }
325 };
326
327 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
329 Ok(pool) => pool,
330 Err(_) => {
331 return Err((
332 Status::InternalServerError,
333 Json(json!({
334 "error": "Database error",
335 "message": "Failed to connect to platform database"
336 }))
337 ));
338 }
339 };
340
341 match db::app::get_app_by_id(&pool, app_id).await {
342 Ok(app) => Ok(Json(app)),
343 Err(_) => {
344 Err((
345 Status::NotFound,
346 Json(json!({
347 "error": "App not found",
348 "message": format!("App with ID {} could not be found", app_id)
349 }))
350 ))
351 }
352 }
353}
354
355#[post("/platform/<platform_id>/apps", format = "json", data = "<app_request>")]
367pub async fn create_app(
368 platform_id: i64,
369 app_request: Json<CreateAppRequest>,
370 db_manager: &State<Arc<DatabaseManager>>,
371) -> Result<Json<App>, (Status, Json<Value>)> {
372 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
374 Ok(platform) => platform,
375 Err(_) => {
376 return Err((
377 Status::NotFound,
378 Json(json!({
379 "error": "Platform not found",
380 "message": format!("Platform with ID {} does not exist", platform_id)
381 }))
382 ));
383 }
384 };
385
386 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
388 Ok(pool) => pool,
389 Err(_) => {
390 return Err((
391 Status::InternalServerError,
392 Json(json!({
393 "error": "Database error",
394 "message": "Failed to connect to platform database"
395 }))
396 ));
397 }
398 };
399
400 match db::app::create_app(
401 &pool,
402 &app_request.name,
403 app_request.org_id,
404 None,
405 None,
406 None,
407 None,
408 ).await {
409 Ok(app) => Ok(Json(app)),
410 Err(_) => {
411 Err((
412 Status::InternalServerError,
413 Json(json!({
414 "error": "Database error",
415 "message": "Failed to create application"
416 }))
417 ))
418 }
419 }
420}
421
422#[post("/platform/<platform_id>/apps/<app_id>", format = "json", data = "<app_request>")]
435pub async fn update_app(
436 platform_id: i64,
437 app_request: Json<UpdateAppRequest>,
438 db_manager: &State<Arc<DatabaseManager>>,
439 app_id: i64,
440) -> Result<Json<App>, (Status, Json<Value>)> {
441 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
443 Ok(platform) => platform,
444 Err(_) => {
445 return Err((
446 Status::NotFound,
447 Json(json!({
448 "error": "Platform not found",
449 "message": format!("Platform with ID {} does not exist", platform_id)
450 }))
451 ));
452 }
453 };
454
455 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
457 Ok(pool) => pool,
458 Err(_) => {
459 return Err((
460 Status::InternalServerError,
461 Json(json!({
462 "error": "Database error",
463 "message": "Failed to connect to platform database"
464 }))
465 ));
466 }
467 };
468
469 match db::app::update_app(
470 &pool,
471 app_id,
472 Some(&app_request.name),
473 None,
474 None,
475 None,
476 None,
477 None,
478 ).await {
479 Ok(app) => Ok(Json(app)),
480 Err(_) => {
481 Err((
482 Status::InternalServerError,
483 Json(json!({
484 "error": "Database error",
485 "message": "Failed to update application"
486 }))
487 ))
488 }
489 }
490}
491
492#[get("/platform/<platform_id>/apps/<app_id>/stats")]
504pub async fn get_app_stats(
505 platform_id: i64,
506 app_id: String,
507 db_manager: &State<Arc<DatabaseManager>>
508) -> Result<Json<AppStats>, (Status, Json<Value>)> {
509 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
511 Ok(platform) => platform,
512 Err(_) => {
513 return Err((
514 Status::NotFound,
515 Json(json!({
516 "error": "Platform not found",
517 "message": format!("Platform with ID {} does not exist", platform_id)
518 }))
519 ));
520 }
521 };
522
523 let _pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
525 Ok(pool) => pool,
526 Err(_) => {
527 return Err((
528 Status::InternalServerError,
529 Json(json!({
530 "error": "Database error",
531 "message": "Failed to connect to platform database"
532 }))
533 ));
534 }
535 };
536
537 let app_stats = AppStats {
539 cpu_usage: 0.0,
540 memory_usage: 0,
541 disk_usage: 0,
542 requests_per_second: 0.0,
543 response_time_ms: 0,
544 };
545 Ok(Json(app_stats))
546}
547
548#[put("/platform/<platform_id>/apps/<app_id>/start")]
560pub async fn start_app(
561 platform_id: i64,
562 app_id: String,
563 db_manager: &State<Arc<DatabaseManager>>
564) -> Result<Json<Application>, (Status, Json<Value>)> {
565 todo!()
568}
569
570#[put("/platform/<platform_id>/apps/<app_id>/stop")]
582pub async fn stop_app(
583 platform_id: i64,
584 app_id: String,
585 db_manager: &State<Arc<DatabaseManager>>
586) -> Result<Json<Application>, (Status, Json<Value>)> {
587 todo!()
590}
591
592#[put("/platform/<platform_id>/apps/<app_id>/scale", format = "json", data = "<scale>")]
605pub async fn scale_app(
606 platform_id: i64,
607 app_id: String,
608 scale: Json<ScaleRequest>,
609 db_manager: &State<Arc<DatabaseManager>>
610) -> Result<Json<Application>, (Status, Json<Value>)> {
611 todo!()
614}
615
616#[delete("/platform/<platform_id>/apps/<app_id>")]
628pub async fn delete_app(
629 platform_id: i64,
630 app_id: String,
631 db_manager: &State<Arc<DatabaseManager>>,
632) -> Result<Json<Value>, (Status, Json<Value>)> {
633 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
635 Ok(platform) => platform,
636 Err(_) => {
637 return Err((
638 Status::NotFound,
639 Json(json!({
640 "error": "Platform not found",
641 "message": format!("Platform with ID {} does not exist", platform_id)
642 }))
643 ));
644 }
645 };
646
647 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
649 Ok(pool) => pool,
650 Err(_) => {
651 return Err((
652 Status::InternalServerError,
653 Json(json!({
654 "error": "Database error",
655 "message": "Failed to connect to platform database"
656 }))
657 ));
658 }
659 };
660
661 match app_id.parse::<i64>() {
662 Ok(id) => {
663 match db::app::delete_app(&pool, id).await {
664 Ok(_) => Ok(Json(json!({ "status": "deleted" }))),
665 Err(_) => {
666 Err((
667 Status::InternalServerError,
668 Json(json!({
669 "error": "Database error",
670 "message": "Failed to delete application"
671 }))
672 ))
673 }
674 }
675 }
676 Err(e) => {
677 Err((
678 Status::BadRequest,
679 Json(json!({
680 "error": "Invalid ID format",
681 "message": format!("The application ID must be a valid integer: {}", e)
682 }))
683 ))
684 }
685 }
686}
687
688#[post(
715 "/platform/<platform_id>/apps/<app_id>/releases/<release_version>/upload",
716 format = "multipart/form-data",
717 data = "<data>"
718)]
719pub async fn release(
720 platform_id: i64,
721 app_id: String,
722 release_version: String,
723 content_type: &ContentType,
724 data: Data<'_>,
725 db_manager: &State<Arc<DatabaseManager>>,
726) -> Result<Status, Status> {
727 match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
732 Ok(_) => {
733 super::helpers::release::release(app_id, release_version, content_type, data).await
735 },
736 Err(_) => {
737 Err(Status::NotFound)
739 }
740 }
741}
742
743#[get("/platform/<platform_id>/apps/<app_id>/instances?<page>&<per_page>")]
745pub async fn list_instances(
746 platform_id: i64,
747 app_id: i64,
748 page: Option<i64>,
749 per_page: Option<i64>,
750 db_manager: &State<Arc<DatabaseManager>>,
751) -> Result<Json<Value>, (Status, Json<Value>)> {
752 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
754 Ok(platform) => platform,
755 Err(_) => {
756 return Err((
757 Status::NotFound,
758 Json(json!({
759 "error": "Platform not found",
760 "message": format!("Platform with ID {} does not exist", platform_id)
761 }))
762 ));
763 }
764 };
765
766 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
768 Ok(pool) => pool,
769 Err(_) => {
770 return Err((
771 Status::InternalServerError,
772 Json(json!({
773 "error": "Database error",
774 "message": "Failed to connect to platform database"
775 }))
776 ));
777 }
778 };
779
780 match (page, per_page) {
781 (Some(p), Some(pp)) => {
782 let instances = match db::app::list_instances(&pool, app_id, p, pp).await {
783 Ok(instances) => instances,
784 Err(_) => {
785 return Err((
786 Status::InternalServerError,
787 Json(json!({
788 "error": "Database error",
789 "message": "Failed to retrieve instances"
790 }))
791 ));
792 }
793 };
794
795 let total_count = match db::app::count_instances_by_app(&pool, app_id).await {
796 Ok(count) => count,
797 Err(_) => {
798 return Err((
799 Status::InternalServerError,
800 Json(json!({
801 "error": "Database error",
802 "message": "Failed to count instances"
803 }))
804 ));
805 }
806 };
807
808 let total_pages = (total_count as f64 / pp as f64).ceil() as i64;
809
810 let response = json!({
811 "instances": instances,
812 "pagination": {
813 "page": p,
814 "per_page": pp,
815 "total_count": total_count,
816 "total_pages": total_pages
817 }
818 });
819
820 Ok(Json(response))
821 }
822 _ => Err((
823 Status::BadRequest,
824 Json(json!({
825 "error": "Missing pagination parameters",
826 "message": "Please provide both 'page' and 'per_page' parameters"
827 }))
828 ))
829 }
830}