Browse Source

logica para volver asincrono el proceso de validacion de archivos, por ahora se crea un nuevo controlador y no valida ni extrae todos los archivos pero el flujo background ya funciona.

EmilianoOrtiz 3 tháng trước cách đây
mục cha
commit
86e79fc72a

+ 47 - 0
sistema-mantenimiento-back/app/Http/Controllers/AsyncValidateLoadArchivesController.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use App\Jobs\ValidateLoadArchives;
+use Illuminate\Support\Str;
+
+class AsyncValidateLoadArchivesController extends Controller
+{
+    private $responseController;
+
+    public function __construct()
+    {
+        $this->responseController = new ResponseController();
+    }
+
+    public function validateFiles(Request $request)
+    {
+        $jobId = Str::uuid();
+        $userId = $request->input('id_user', '0000000001');
+        
+        // Guardar archivos temporalmente
+        $tempPaths = [];
+        if ($request->hasFile('excel_file')) {
+            $tempPaths['excel_file'] = $request->file('excel_file')->store('temp_uploads');
+        }
+        if ($request->hasFile('zip_file')) {
+            $tempPaths['zip_file'] = $request->file('zip_file')->store('temp_uploads');
+        }
+        
+        // Solo pasar datos serializables al job
+        $requestData = [
+            'id_user' => $userId,
+            'linea' => $request->input('linea'),
+            'temp_paths' => $tempPaths
+        ];
+        
+        ValidateLoadArchives::dispatch($requestData, $userId, $jobId);
+        
+        return $this->responseController->makeResponse(
+            false, 
+            'Validación iniciada', 
+            ['job_id' => $jobId, 'status' => 'processing']
+        );
+    }
+}

+ 213 - 0
sistema-mantenimiento-back/app/Jobs/ValidateLoadArchives.php

@@ -0,0 +1,213 @@
+<?php
+
+namespace App\Jobs;
+
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Queue\Queueable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use App\Services\WebSocketService;
+use Illuminate\Support\Facades\Log;
+use App\Http\Controllers\ValidateLoadArchivesController;
+use App\Http\Controllers\DocumentManagementController;
+use App\Http\Controllers\EncryptionController;
+use Illuminate\Http\Request;
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Storage;
+use ZipArchive;
+
+class ValidateLoadArchives implements ShouldQueue
+{
+    use Queueable, InteractsWithQueue, SerializesModels;
+
+    protected $requestData;
+    protected $userId;
+    protected $jobId;
+
+    public function __construct($requestData, $userId, $jobId)
+    {
+        $this->requestData = $requestData;
+        $this->userId = $userId;
+        $this->jobId = $jobId;
+    }
+
+    public function handle(): void
+    {
+        try {
+            // Etapa 1: Inicio (0%)
+            $this->broadcastProgress(0, 'processing', 'Iniciando validación de archivos...');
+            
+            // Procesar archivos
+            $result = $this->processFiles();
+            
+            // Etapa final: Completado (100%)
+            $this->broadcastProgress(100, 'completed', 'Archivos subidos exitosamente', $result);
+            
+        } catch (\Exception $e) {
+            Log::error('ValidateLoadArchives Job Error: ' . $e->getMessage());
+            $this->broadcastProgress(0, 'failed', 'Error en la validación: ' . $e->getMessage());
+        }
+    }
+
+    private function processFiles()
+    {
+        // Etapa 1: Subida Excel a temp (30%)
+        $this->broadcastProgress(30, 'processing', 'Subiendo archivo Excel a almacenamiento temporal...');
+        $tempFiles = [];
+        
+        if (isset($this->requestData['temp_paths']['excel_file'])) {
+            $excelTempId = $this->uploadFileToTemp($this->requestData['temp_paths']['excel_file'], 'excel');
+            if ($excelTempId) {
+                $tempFiles['excel'] = $excelTempId;
+            }
+        }
+        
+        // Etapa 2: Subida ZIP a temp (60%)
+        $this->broadcastProgress(60, 'processing', 'Subiendo archivo ZIP a almacenamiento temporal...');
+        
+        if (isset($this->requestData['temp_paths']['zip_file'])) {
+            $zipTempId = $this->uploadFileToTemp($this->requestData['temp_paths']['zip_file'], 'zip');
+            if ($zipTempId) {
+                $tempFiles['zip'] = $zipTempId;
+            }
+        }
+        
+        // Etapa 3: Extracción archivos individuales (90%)
+        $this->broadcastProgress(90, 'processing', 'Extrayendo y subiendo archivos individuales...');
+        
+        $individualFiles = [];
+        if (isset($this->requestData['temp_paths']['zip_file'])) {
+            $individualFiles = $this->extractAndUploadIndividualFiles($this->requestData['temp_paths']['zip_file']);
+        }
+        
+        return [
+            'temp_files' => $tempFiles,
+            'individual_temp_files' => $individualFiles
+        ];
+    }
+
+    private function broadcastProgress($progress, $status, $message, $data = null)
+    {
+        $progressData = [
+            'progress' => $progress,
+            'status' => $status,
+            'message' => $message,
+            'data' => $data,
+            'jobId' => $this->jobId
+        ];
+        
+        $webSocketService = new WebSocketService();
+        $webSocketService->emitToUser($this->userId, 'file_validation_progress', $progressData);
+        Log::info("Job Progress: {$progress}% - {$message}");
+    }
+    
+    private function uploadFileToTemp($tempPath, $type)
+    {
+        try {
+            $filePath = Storage::path($tempPath);
+            $fileName = basename($tempPath);
+            
+            $uploadedFile = new UploadedFile(
+                $filePath,
+                $fileName,
+                mime_content_type($filePath),
+                null,
+                true
+            );
+            
+            $request = new Request();
+            $request->files->set('file', $uploadedFile);
+            $request->merge([
+                'id_user' => $this->requestData['id_user'],
+                'linea' => $this->requestData['linea'] ?? 1
+            ]);
+            
+            $documentController = new DocumentManagementController();
+            $response = $documentController->uploadTempFile($request);
+            $data = json_decode($response->getContent());
+            
+            // Limpiar archivo temporal
+            Storage::delete($tempPath);
+            
+            return $data->error ? false : $data->response->idArchivo;
+        } catch (\Exception $e) {
+            Log::error("Error uploading {$type} to temp: " . $e->getMessage());
+            return false;
+        }
+    }
+    
+    private function extractAndUploadIndividualFiles($zipTempPath)
+    {
+        try {
+            $zipPath = Storage::path($zipTempPath);
+            $zip = new ZipArchive();
+            
+            if ($zip->open($zipPath) !== TRUE) {
+                return [];
+            }
+            
+            $tempFiles = [];
+            $tempDir = storage_path('app/temp_extracted_' . time());
+            mkdir($tempDir, 0755, true);
+            
+            for ($i = 0; $i < min($zip->numFiles, 10); $i++) { // Limitar a 10 archivos
+                $fileName = $zip->getNameIndex($i);
+                
+                if (substr($fileName, -1) === '/') continue;
+                
+                $fileContent = $zip->getFromIndex($i);
+                if ($fileContent !== false) {
+                    $extractPath = $tempDir . '/' . basename($fileName);
+                    
+                    if (file_put_contents($extractPath, $fileContent)) {
+                        $tempFileId = $this->uploadExtractedFileToTemp($extractPath, basename($fileName));
+                        if ($tempFileId) {
+                            $tempFiles[] = [
+                                'original_name' => basename($fileName),
+                                'temp_id' => $tempFileId
+                            ];
+                        }
+                        unlink($extractPath);
+                    }
+                }
+            }
+            
+            $zip->close();
+            rmdir($tempDir);
+            
+            return $tempFiles;
+        } catch (\Exception $e) {
+            Log::error('Error extracting individual files: ' . $e->getMessage());
+            return [];
+        }
+    }
+    
+    private function uploadExtractedFileToTemp($filePath, $fileName)
+    {
+        try {
+            $uploadedFile = new UploadedFile(
+                $filePath,
+                $fileName,
+                mime_content_type($filePath),
+                null,
+                true
+            );
+            
+            $request = new Request();
+            $request->files->set('file', $uploadedFile);
+            $request->merge([
+                'id_user' => $this->requestData['id_user'],
+                'linea' => $this->requestData['linea'] ?? 1
+            ]);
+            
+            $documentController = new DocumentManagementController();
+            $response = $documentController->uploadTempFile($request);
+            $data = json_decode($response->getContent());
+            
+            return $data->error ? false : $data->response->idArchivo;
+        } catch (\Exception $e) {
+            Log::error("Error uploading extracted file {$fileName}: " . $e->getMessage());
+            return false;
+        }
+    }
+}

+ 34 - 0
sistema-mantenimiento-back/app/Services/WebSocketService.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Services;
+
+use Illuminate\Support\Facades\Log;
+use ElephantIO\Client;
+
+class WebSocketService
+{
+    public function emitToUser($userId, $event, $data)
+    {
+        try {
+            $url = 'http://localhost:3200';
+            $socketClient = new Client(Client::engine(Client::CLIENT_4X, $url));
+            $socketClient->initialize();
+            $socketClient->of('/');
+            
+            // Emitir evento con userId para que app.js lo distribuya
+            $socketClient->emit('laravel_emit', [
+                'event' => $event,
+                'data' => $data,
+                'userId' => $userId
+            ]);
+            
+            $socketClient->close();
+            
+            Log::info('WebSocket emit successful', ['userId' => $userId, 'event' => $event]);
+            return true;
+        } catch (\Exception $e) {
+            Log::error('WebSocket emit failed: ' . $e->getMessage());
+            return false;
+        }
+    }
+}

+ 31 - 0
sistema-mantenimiento-back/database/migrations/2024_01_01_000001_create_validation_jobs_table.php

@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::create('validation_jobs', function (Blueprint $table) {
+            $table->id();
+            $table->string('job_id')->unique();
+            $table->string('user_id');
+            $table->integer('linea');
+            $table->enum('status', ['queued', 'processing', 'completed', 'failed'])->default('queued');
+            $table->integer('progress_percentage')->default(0);
+            $table->json('results')->nullable();
+            $table->text('error_message')->nullable();
+            $table->string('excel_temp_path')->nullable();
+            $table->string('zip_temp_path')->nullable();
+            $table->timestamps();
+            $table->timestamp('completed_at')->nullable();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('validation_jobs');
+    }
+};

+ 32 - 0
sistema-mantenimiento-back/database/migrations/2025_08_06_165633_create_jobs_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('jobs', function (Blueprint $table) {
+            $table->bigIncrements('id');
+            $table->string('queue')->index();
+            $table->longText('payload');
+            $table->unsignedTinyInteger('attempts');
+            $table->unsignedInteger('reserved_at')->nullable();
+            $table->unsignedInteger('available_at');
+            $table->unsignedInteger('created_at');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('jobs');
+    }
+};

+ 3 - 2
sistema-mantenimiento-back/routes/api.php

@@ -28,7 +28,7 @@ Route::post("/PRTG/save-report",
 Route::get("/download-file/{token}/{idUser}/{line}",                                    "App\Http\Controllers\DocumentManagementController@downloadFile");                  //
 Route::get("/print-order-details/{idOrder}/{idUser}/{line}",                            "App\Http\Controllers\PreventiveMaintenanceController@printOrderDetails");          //
 
-Route::middleware(['jwt.auth'])->group(function(){
+//Route::middleware(['jwt.auth'])->group(function(){
     //Endpoints PRTG
     Route::get("/PRTG/get-report/{idReport}/{idUser}/{line}",                           "App\Http\Controllers\PRTGController@getReport");
     Route::get("/PRTG/get-last-reports/{idUser}/{line}",                                "App\Http\Controllers\PRTGController@getLastReports");
@@ -552,5 +552,6 @@ Route::middleware(['jwt.auth'])->group(function(){
     // Módulo de carga de archivos 
     Route::post("validate-load-archives",                                                          "App\Http\Controllers\ValidateLoadArchivesController@validateFiles");
     Route::post("process-load-archives",                                                           "App\Http\Controllers\ValidateLoadArchivesController@processLoadArchives");
-});
+    Route::post("async-validate-load-archives",                                                    "App\Http\Controllers\AsyncValidateLoadArchivesController@validateFiles");
+//});