359 lines
12 KiB
PHP
359 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Amministratore;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
/**
|
|
* Servizio per gestione distribuzione multi-server degli archivi amministratori
|
|
*/
|
|
class DistributionService
|
|
{
|
|
/**
|
|
* Migra un amministratore da un server all'altro
|
|
*/
|
|
public static function migrateAdministrator(Amministratore $amministratore, string $targetServerUrl): array
|
|
{
|
|
try {
|
|
Log::info("Inizio migrazione amministratore {$amministratore->codice_amministratore} verso {$targetServerUrl}");
|
|
|
|
// 1. Prepara archivio per migrazione
|
|
$migrationData = $amministratore->prepareForMigration();
|
|
if (!$migrationData['success']) {
|
|
throw new \Exception('Errore preparazione migrazione: ' . $migrationData['error']);
|
|
}
|
|
|
|
// 2. Verifica connettività server target
|
|
$targetHealth = static::checkServerHealth($targetServerUrl);
|
|
if (!$targetHealth['success']) {
|
|
throw new \Exception('Server target non raggiungibile: ' . $targetHealth['error']);
|
|
}
|
|
|
|
// 3. Trasferisce archivio al server target
|
|
$transferResult = static::transferArchive($migrationData['zip_file'], $targetServerUrl, $amministratore);
|
|
if (!$transferResult['success']) {
|
|
throw new \Exception('Errore trasferimento archivio: ' . $transferResult['error']);
|
|
}
|
|
|
|
// 4. Aggiorna configurazione amministratore
|
|
$amministratore->update([
|
|
'server_database' => parse_url($targetServerUrl, PHP_URL_HOST),
|
|
'server_port' => parse_url($targetServerUrl, PHP_URL_PORT) ?: 3306,
|
|
'url_accesso' => $targetServerUrl,
|
|
'stato_sincronizzazione' => 'migrazione',
|
|
'ultimo_backup' => now()
|
|
]);
|
|
|
|
// 5. Notifica server target per attivazione
|
|
$activationResult = static::activateOnTargetServer($targetServerUrl, $amministratore);
|
|
|
|
if ($activationResult['success']) {
|
|
$amministratore->update(['stato_sincronizzazione' => 'attivo']);
|
|
|
|
Log::info("Migrazione completata per amministratore {$amministratore->codice_amministratore}");
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Migrazione completata con successo',
|
|
'new_url' => $targetServerUrl,
|
|
'transfer_id' => $transferResult['transfer_id'] ?? null
|
|
];
|
|
} else {
|
|
throw new \Exception('Errore attivazione su server target: ' . $activationResult['error']);
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error("Errore migrazione amministratore {$amministratore->codice_amministratore}: " . $e->getMessage());
|
|
|
|
// Ripristina stato precedente
|
|
$amministratore->update(['stato_sincronizzazione' => 'errore']);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifica salute e compatibilità di un server NetGesCon
|
|
*/
|
|
public static function checkServerHealth(string $serverUrl): array
|
|
{
|
|
try {
|
|
$response = Http::timeout(10)->get("{$serverUrl}/api/health");
|
|
|
|
if (!$response->successful()) {
|
|
throw new \Exception("Server risponde con codice {$response->status()}");
|
|
}
|
|
|
|
$data = $response->json();
|
|
|
|
// Verifica versione compatibile
|
|
$requiredVersion = config('app.min_version', '1.0.0');
|
|
if (version_compare($data['version'] ?? '0.0.0', $requiredVersion, '<')) {
|
|
throw new \Exception("Versione server incompatibile: {$data['version']} < {$requiredVersion}");
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'server_info' => $data,
|
|
'compatible' => true
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage(),
|
|
'compatible' => false
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trasferisce archivio amministratore a server target
|
|
*/
|
|
private static function transferArchive(string $zipPath, string $targetServerUrl, Amministratore $amministratore): array
|
|
{
|
|
try {
|
|
$response = Http::timeout(300)
|
|
->attach('archive', file_get_contents($zipPath), basename($zipPath))
|
|
->post("{$targetServerUrl}/api/import-administrator", [
|
|
'codice_amministratore' => $amministratore->codice_amministratore,
|
|
'source_server' => config('app.url'),
|
|
'migration_token' => static::generateMigrationToken($amministratore)
|
|
]);
|
|
|
|
if (!$response->successful()) {
|
|
throw new \Exception("Errore HTTP {$response->status()}: " . $response->body());
|
|
}
|
|
|
|
return $response->json();
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attiva amministratore su server target
|
|
*/
|
|
private static function activateOnTargetServer(string $targetServerUrl, Amministratore $amministratore): array
|
|
{
|
|
try {
|
|
$response = Http::timeout(60)->post("{$targetServerUrl}/api/activate-administrator", [
|
|
'codice_amministratore' => $amministratore->codice_amministratore,
|
|
'activation_token' => static::generateMigrationToken($amministratore)
|
|
]);
|
|
|
|
if (!$response->successful()) {
|
|
throw new \Exception("Errore attivazione HTTP {$response->status()}: " . $response->body());
|
|
}
|
|
|
|
return $response->json();
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Genera token sicuro per migrazione
|
|
*/
|
|
private static function generateMigrationToken(Amministratore $amministratore): string
|
|
{
|
|
return hash('sha256', $amministratore->codice_amministratore . $amministratore->created_at . config('app.key'));
|
|
}
|
|
|
|
/**
|
|
* Sincronizza dati tra server per amministratore distribuito
|
|
*/
|
|
public static function syncAdministratorData(Amministratore $amministratore): array
|
|
{
|
|
try {
|
|
if (!$amministratore->server_database) {
|
|
return ['success' => true, 'message' => 'Amministratore su server locale'];
|
|
}
|
|
|
|
$targetUrl = $amministratore->url_accesso;
|
|
if (!$targetUrl) {
|
|
throw new \Exception('URL server target non configurato');
|
|
}
|
|
|
|
// Verifica stato server target
|
|
$healthCheck = static::checkServerHealth($targetUrl);
|
|
if (!$healthCheck['success']) {
|
|
throw new \Exception('Server target non raggiungibile');
|
|
}
|
|
|
|
// Invia richiesta di sincronizzazione
|
|
$response = Http::timeout(30)->post("{$targetUrl}/api/sync-administrator", [
|
|
'codice_amministratore' => $amministratore->codice_amministratore,
|
|
'last_sync' => $amministratore->updated_at,
|
|
'sync_token' => static::generateMigrationToken($amministratore)
|
|
]);
|
|
|
|
if (!$response->successful()) {
|
|
throw new \Exception("Errore sincronizzazione: {$response->status()}");
|
|
}
|
|
|
|
$syncData = $response->json();
|
|
|
|
// Aggiorna timestamp ultima sincronizzazione
|
|
$amministratore->touch();
|
|
|
|
return [
|
|
'success' => true,
|
|
'synced_at' => now(),
|
|
'changes' => $syncData['changes'] ?? 0
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error("Errore sincronizzazione amministratore {$amministratore->codice_amministratore}: " . $e->getMessage());
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ottiene statistiche distribuzione server
|
|
*/
|
|
public static function getDistributionStats(): array
|
|
{
|
|
$stats = [
|
|
'total_administrators' => Amministratore::count(),
|
|
'local_administrators' => Amministratore::whereNull('server_database')->count(),
|
|
'distributed_administrators' => Amministratore::whereNotNull('server_database')->count(),
|
|
'servers' => [],
|
|
'status_distribution' => Amministratore::groupBy('stato_sincronizzazione')
|
|
->selectRaw('stato_sincronizzazione, count(*) as count')
|
|
->pluck('count', 'stato_sincronizzazione')
|
|
->toArray()
|
|
];
|
|
|
|
// Raggruppa per server
|
|
$serverGroups = Amministratore::whereNotNull('server_database')
|
|
->groupBy('server_database')
|
|
->selectRaw('server_database, count(*) as administrators_count')
|
|
->get();
|
|
|
|
foreach ($serverGroups as $group) {
|
|
$stats['servers'][] = [
|
|
'server' => $group->server_database,
|
|
'administrators_count' => $group->administrators_count,
|
|
'health' => 'unknown' // TODO: implementare controllo salute periodico
|
|
];
|
|
}
|
|
|
|
return $stats;
|
|
}
|
|
|
|
/**
|
|
* Routing DNS intelligente per amministratori distribuiti
|
|
*/
|
|
public static function getAdministratorAccessUrl(string $codiceAmministratore): array
|
|
{
|
|
$amministratore = Amministratore::where('codice_amministratore', $codiceAmministratore)->first();
|
|
|
|
if (!$amministratore) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Amministratore non trovato'
|
|
];
|
|
}
|
|
|
|
// Se ha URL specifico, usalo
|
|
if ($amministratore->url_accesso) {
|
|
return [
|
|
'success' => true,
|
|
'url' => $amministratore->url_accesso,
|
|
'server_type' => 'distributed',
|
|
'server' => $amministratore->server_database
|
|
];
|
|
}
|
|
|
|
// Altrimenti è su server locale
|
|
return [
|
|
'success' => true,
|
|
'url' => config('app.url'),
|
|
'server_type' => 'local',
|
|
'server' => 'localhost'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Backup automatico distribuito
|
|
*/
|
|
public static function performDistributedBackup(Amministratore $amministratore): array
|
|
{
|
|
try {
|
|
// Backup locale
|
|
$localBackup = $amministratore->createDatabaseBackup();
|
|
if (!$localBackup['success']) {
|
|
throw new \Exception('Errore backup locale: ' . $localBackup['error']);
|
|
}
|
|
|
|
// Se distribuito, backup anche remoto
|
|
if ($amministratore->server_database && $amministratore->url_accesso) {
|
|
$remoteBackup = static::triggerRemoteBackup($amministratore);
|
|
|
|
return [
|
|
'success' => true,
|
|
'local_backup' => $localBackup,
|
|
'remote_backup' => $remoteBackup
|
|
];
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'local_backup' => $localBackup,
|
|
'remote_backup' => null
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger backup remoto
|
|
*/
|
|
private static function triggerRemoteBackup(Amministratore $amministratore): array
|
|
{
|
|
try {
|
|
$response = Http::timeout(120)->post("{$amministratore->url_accesso}/api/backup-administrator", [
|
|
'codice_amministratore' => $amministratore->codice_amministratore,
|
|
'backup_token' => static::generateMigrationToken($amministratore)
|
|
]);
|
|
|
|
if (!$response->successful()) {
|
|
throw new \Exception("Errore backup remoto: {$response->status()}");
|
|
}
|
|
|
|
return $response->json();
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
}
|