fixing bugs

This commit is contained in:
DioCrafts
2025-03-23 22:44:18 +01:00
parent 72de043184
commit 9a9fd72f61
54 changed files with 2593 additions and 513 deletions
+40 -364
View File
@@ -75,13 +75,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize path service
let path_service = Arc::new(PathService::new(storage_path.clone()));
// Initialize ID mapping service with optimizer
let id_mapping_path = storage_path.join("folder_ids.json");
let base_id_mapping_service = Arc::new(
IdMappingService::new(id_mapping_path).await
.expect("Failed to initialize ID mapping service")
// Initialize ID mapping service for folders
let folder_id_mapping_path = storage_path.join("folder_ids.json");
let folder_id_mapping_service = Arc::new(
IdMappingService::new(folder_id_mapping_path).await
.expect("Failed to initialize folder ID mapping service")
);
// Initialize ID mapping service for files
let file_id_mapping_path = storage_path.join("file_ids.json");
let file_id_mapping_service = Arc::new(
IdMappingService::new(file_id_mapping_path).await
.expect("Failed to initialize file ID mapping service")
);
// For backward compatibility, use folder ID service as the base ID mapping service
let base_id_mapping_service = folder_id_mapping_service.clone();
// Create optimized ID mapping service with batch processing and caching
let id_mapping_optimizer = Arc::new(
IdMappingOptimizer::new(base_id_mapping_service.clone())
@@ -150,7 +160,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let file_repository = Arc::new(FileFsRepository::new_with_processor(
storage_path.clone(),
storage_mediator,
base_id_mapping_service.clone(), // Use the base service, not the optimizer
file_id_mapping_service.clone(), // Use the file-specific ID mapping service
path_service.clone(),
metadata_cache.clone(), // Clone to keep a reference for later use
parallel_processor
@@ -176,9 +186,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize auth services if enabled and database connection is available
let auth_services = if config.features.enable_auth && db_pool.is_some() {
match create_auth_services(&config, db_pool.as_ref().unwrap().clone()).await {
match create_auth_services(
&config,
db_pool.as_ref().unwrap().clone(),
Some(folder_service.clone()) // Pasar el servicio de carpetas para creación automática de carpetas de usuario
).await {
Ok(services) => {
tracing::info!("Authentication services initialized successfully");
tracing::info!("Authentication services initialized successfully with folder service");
Some(services)
},
Err(e) => {
@@ -194,7 +208,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let core_services = common::di::CoreServices {
path_service: path_service.clone(),
cache_manager: Arc::new(infrastructure::services::cache_manager::StorageCacheManager::default()),
id_mapping_service: base_id_mapping_service.clone(),
id_mapping_service: base_id_mapping_service.clone(), // We keep using the folder ID mapping service for core services
config: config.clone(),
};
@@ -209,13 +223,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
folder_repository: Arc::new(FolderFsRepository::new(
storage_path.clone(),
storage_mediator_stub.clone(),
base_id_mapping_service.clone(),
folder_id_mapping_service.clone(),
path_service.clone()
)),
file_repository: Arc::new(FileFsRepository::new(
storage_path.clone(),
storage_mediator_stub.clone(),
base_id_mapping_service.clone(),
file_id_mapping_service.clone(),
path_service.clone(),
metadata_cache.clone(),
)),
@@ -288,367 +302,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
// Start server with clear message
let addr = SocketAddr::from(([127, 0, 0, 1], 8085));
let addr = SocketAddr::from(([127, 0, 0, 1], 8086));
tracing::info!("Starting OxiCloud server on http://{}", addr);
// Start the server
tracing::info!("Authentication system initialized successfully");
// Use a much simpler direct approach with hyper
// Import the redirect middleware
use crate::interfaces::middleware::redirect::redirect_middleware;
// Apply the redirect middleware to handle legacy routes
app = app.layer(axum::middleware::from_fn(redirect_middleware));
// Create a standard TCP listener
let listener = tokio::net::TcpListener::bind(addr).await?;
tracing::info!("Server binding to http://{}", addr);
tracing::info!("Starting server with Axum routes...");
// Most basic approach using axum-core functionality
use std::net::TcpListener as StdTcpListener;
// For Axum 0.8, we need to properly handle state
// Add global state to the router
let app = app.with_state(app_state);
// Create TCP listener using standard library
let listener = StdTcpListener::bind(addr).expect("Failed to bind to address");
// Make listener non-blocking
listener.set_nonblocking(true).expect("Failed to set non-blocking");
// Convert to tokio listener
let listener = tokio::net::TcpListener::from_std(listener).expect("Failed to convert listener");
tracing::info!("Server listening on http://{}", addr);
// Spawn a task to handle incoming connections
tokio::spawn(async move {
// No necesitamos realmente el service para este enfoque básico
// Eliminamos app.into_service() ya que solo estamos respondiendo con un mensaje estático
loop {
match listener.accept().await {
Ok((mut socket, _)) => {
// Process each connection
tracing::debug!("Accepted connection from: {:?}", socket.peer_addr());
// Process the connection properly with tokio I/O
tokio::spawn(async move {
// Para depurar, recibimos la solicitud
use tokio::io::{AsyncReadExt, AsyncWriteExt};
let mut buffer = [0; 1024];
let n = match socket.read(&mut buffer).await {
Ok(n) => n,
Err(e) => {
tracing::error!("Failed to read from socket: {}", e);
return;
}
};
// Convertimos el buffer a String para poder analizarlo
let request = String::from_utf8_lossy(&buffer[0..n]);
tracing::debug!("Received request: {}", request);
// Analizamos la primera línea para obtener el método y la ruta
let first_line = request.lines().next().unwrap_or("");
let parts: Vec<&str> = first_line.split_whitespace().collect();
if parts.len() >= 2 {
let _method = parts[0]; // GET, POST, etc.
let path = parts[1]; // /login, /, etc.
tracing::debug!("Request for path: {}", path);
// Manejo de CORS para peticiones preflight
let response = if _method == "OPTIONS" {
// Responder a las peticiones preflight para CORS
"HTTP/1.1 204 No Content\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\r\nAccess-Control-Allow-Headers: Content-Type, Authorization\r\nAccess-Control-Max-Age: 86400\r\n\r\n".to_string()
} else if path == "/login" || path == "/login/" {
// Servir la página de login
let login_html = include_str!("../static/login.html");
let content_length = login_html.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\n\r\n{}",
content_length, login_html)
} else if path.starts_with("/css/") {
// Intentamos servir archivos CSS
match path {
"/css/style.css" => {
let css = include_str!("../static/css/style.css");
let content_length = css.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: text/css\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, css)
},
"/css/auth.css" => {
// Usamos aquí la ruta completa para asegurarnos que el compilador encuentra el archivo
let css = std::fs::read_to_string("/home/torrefacto/OxiCloud/static/css/auth.css")
.unwrap_or_else(|e| {
tracing::error!("Failed to read auth.css: {}", e);
"/* Error loading auth.css */".to_string()
});
let content_length = css.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: text/css\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, css)
},
_ => {
// Archivo CSS no encontrado
tracing::debug!("CSS file not found: {}", path);
"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\n\r\nNot Found".to_string()
}
}
} else if path.starts_with("/js/") {
// Intentamos servir archivos JavaScript
match path {
"/js/auth.js" => {
let js = include_str!("../static/js/auth.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/i18n.js" => {
let js = include_str!("../static/js/i18n.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/app.js" => {
let js = include_str!("../static/js/app.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/languageSelector.js" => {
let js = include_str!("../static/js/languageSelector.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/fileRenderer.js" => {
let js = include_str!("../static/js/fileRenderer.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/contextMenus.js" => {
let js = include_str!("../static/js/contextMenus.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/fileOperations.js" => {
let js = include_str!("../static/js/fileOperations.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
"/js/ui.js" => {
let js = include_str!("../static/js/ui.js");
let content_length = js.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/javascript\r\nContent-Length: {}\r\n\r\n{}",
content_length, js)
},
_ => {
// Archivo JS no encontrado
tracing::debug!("JS file not found: {}", path);
"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\n\r\nNot Found".to_string()
}
}
} else if path == "/favicon.ico" {
// Servir el favicon (lo omitimos para simplificar)
"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\n\r\nNot Found".to_string()
} else if path == "/locales/en.json" || path == "/static/locales/en.json" {
// Servir las traducciones en inglés
let en_json = include_str!("../static/locales/en.json");
let content_length = en_json.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, en_json)
} else if path == "/locales/es.json" || path == "/static/locales/es.json" {
// Servir las traducciones en español
let es_json = include_str!("../static/locales/es.json");
let content_length = es_json.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, es_json)
} else if path == "/api/i18n/locales/en" {
// API para obtener las traducciones en inglés
let en_json = include_str!("../static/locales/en.json");
let content_length = en_json.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, en_json)
} else if path == "/api/i18n/locales/es" {
// API para obtener las traducciones en español
let es_json = include_str!("../static/locales/es.json");
let content_length = es_json.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, es_json)
} else if path == "/api/auth/login" && _method == "POST" {
// API de login (mock simple para pruebas)
// Extraer el cuerpo de la solicitud (asumimos JSON)
let body_start = request.find("\r\n\r\n").unwrap_or(0) + 4;
let request_body = &request[body_start..];
tracing::debug!("Login request body: {}", request_body);
// Respuesta simulada con un token JWT válido
// Token contiene: {
// "sub": "123",
// "name": "testuser",
// "email": "test@example.com",
// "role": "user",
// "iat": 1714435200,
// "exp": 1746057600
// }
// iat = 1 de mayo 2024, exp = 1 de mayo 2025 (en segundos desde epoch)
let response_body = r#"{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoidGVzdHVzZXIiLCJlbWFpbCI6InRlc3RAZXhhbXBsZS5jb20iLCJyb2xlIjoidXNlciIsImlhdCI6MTcxNDQzNTIwMCwiZXhwIjoxNzQ2MDU3NjAwfQ.gMfH5JV9oKCGCJBQz98RDgTxHH7Sxm5tYxCAxRJOkMU",
"refreshToken": "refresh-token-mock",
"user": {
"id": "123",
"username": "testuser",
"email": "test@example.com",
"role": "user"
}
}"#;
let content_length = response_body.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path == "/api/auth/register" && _method == "POST" {
// API de registro (mock simple)
let response_body = r#"{
"success": true,
"message": "User registered successfully"
}"#;
let content_length = response_body.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path == "/api/auth/refresh" && _method == "POST" {
// API de refresh token (mock simple)
let response_body = r#"{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoidGVzdHVzZXIiLCJlbWFpbCI6InRlc3RAZXhhbXBsZS5jb20iLCJyb2xlIjoidXNlciIsImlhdCI6MTcxNDQzNTIwMCwiZXhwIjoxNzQ2MDU3NjAwfQ.gMfH5JV9oKCGCJBQz98RDgTxHH7Sxm5tYxCAxRJOkMU",
"refreshToken": "new-refresh-token-mock"
}"#;
let content_length = response_body.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path == "/api/auth/admin-setup" && _method == "POST" {
// API de configuración de admin (mock simple)
let response_body = r#"{
"success": true,
"message": "Admin user created successfully"
}"#;
let content_length = response_body.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path.starts_with("/api/folders") {
// Actually list folders from the storage directory
let folders = std::fs::read_dir("./storage")
.unwrap_or_else(|_| std::fs::read_dir("./").unwrap())
.filter_map(Result::ok)
.filter(|entry| {
entry.path().is_dir() &&
!entry.file_name().to_string_lossy().starts_with(".")
})
.map(|entry| {
let name = entry.file_name().to_string_lossy().to_string();
let id = format!("folder-{}", name.replace(" ", "-"));
format!(r#"{{
"id": "{}",
"name": "{}",
"parent_id": null,
"created_at": 1714435200,
"modified_at": 1714435200
}}"#, id, name)
})
.collect::<Vec<String>>()
.join(",");
let response_body = format!("[{}]", folders);
let content_length = response_body.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path == "/api/files" {
// Actually list files from the storage directory
let files = std::fs::read_dir("./storage")
.unwrap_or_else(|_| std::fs::read_dir("./").unwrap())
.filter_map(Result::ok)
.filter(|entry| {
entry.path().is_file() &&
!entry.file_name().to_string_lossy().starts_with(".")
})
.map(|entry| {
let path = entry.path();
let name = entry.file_name().to_string_lossy().to_string();
let id = format!("file-{}", name.replace(" ", "-").replace(",", ""));
let size = entry.metadata().map(|m| m.len()).unwrap_or(0);
format!(r#"{{
"id": "{}",
"name": "{}",
"size": {},
"mime_type": "application/octet-stream",
"created_at": 1714435200,
"modified_at": 1714435200,
"folder_id": null
}}"#, id, name, size)
})
.collect::<Vec<String>>()
.join(",");
let response_body = format!("[{}]", files);
let content_length = response_body.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path == "/api/files/upload" && _method == "POST" {
// Mock API endpoint for file uploads
let response_body = r#"{
"id": "mock-file-id",
"name": "uploaded-file.pdf",
"size": 1024,
"mime_type": "application/pdf",
"created_at": 1714435200,
"modified_at": 1714435200
}"#;
let content_length = response_body.len();
format!("HTTP/1.1 201 Created\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: {}\r\n\r\n{}",
content_length, response_body)
} else if path == "/" {
// Servir la página principal (index.html) en lugar de redireccionar a login
// Esto evita el bucle infinito de redirecciones
let index_html = include_str!("../static/index.html");
let content_length = index_html.len();
format!("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\n\r\n{}",
content_length, index_html)
} else {
// Cualquier otra ruta, 404
tracing::debug!("Route not found: {}", path);
"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\n\r\nNot Found".to_string()
};
// Enviar respuesta
if let Err(e) = socket.write_all(response.as_bytes()).await {
tracing::error!("Failed to write response to socket: {}", e);
} else {
tracing::debug!("Successfully wrote HTTP response for {}", path);
}
} else {
// Solicitud malformada
let response = "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: 11\r\n\r\nBad Request";
if let Err(e) = socket.write_all(response.as_bytes()).await {
tracing::error!("Failed to write error response to socket: {}", e);
}
}
});
}
Err(e) => {
tracing::error!("Error accepting connection: {}", e);
}
}
}
});
tracing::info!("Server started successfully");
// Keep the main thread alive
tokio::signal::ctrl_c().await?;
// Use axum's serve function with the router with state
axum::serve(listener, app).await?;
tracing::info!("Server shutdown completed");