Files
MediaCollectorLibary/app/Controllers/SyncController.php
Lars Behrends 73d8441787 i dont know
2025-10-20 23:40:55 +02:00

295 lines
9.9 KiB
PHP

<?php
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use App\Models\Source;
use App\Models\SyncLog;
use App\Services\JellyfinSyncService;
use App\Services\LocalSyncService;
use App\Services\SambaSyncService;
use App\Services\NfsSyncService;
class SyncController extends AdminBaseController
{
private $source;
private $syncLog;
private $syncServices = [];
public function __construct(\PDO $pdo, \Slim\Views\Twig $view)
{
parent::__construct($pdo, $view);
$this->source = new Source($pdo);
$this->syncLog = new SyncLog($pdo);
// Initialize sync services
$this->syncServices = [
'jellyfin' => new JellyfinSyncService($pdo),
'local' => new LocalSyncService($pdo),
'samba' => new SambaSyncService($pdo),
'nfs' => new NfsSyncService($pdo)
];
}
// Show sync dashboard
public function index(Request $request, Response $response, array $args): Response
{
// Get recent sync logs
$recentLogs = $this->syncLog->orderBy('created_at', 'desc')->limit(10)->get();
// Get sync statistics
$stats = [
'total_syncs' => $this->syncLog->count(),
'successful_syncs' => $this->syncLog->where('status', 'completed')->count(),
'failed_syncs' => $this->syncLog->where('status', 'failed')->count(),
'pending_syncs' => $this->syncLog->where('status', 'pending')->count(),
];
return $this->render($response, 'admin/sync/index.twig', [
'recent_logs' => $recentLogs,
'stats' => $stats,
'current_route' => 'sync'
]);
}
// Start a new sync
public function start(Request $request, Response $response, array $args): Response
{
$data = $request->getParsedBody();
$type = $data['type'] ?? 'full'; // full, scan, update
$sourceId = $data['source_id'] ?? null;
try {
// Create a new sync log
$logData = [
'source_id' => $sourceId,
'sync_type' => $type,
'status' => 'pending',
'started_at' => date('Y-m-d H:i:s'),
'created_at' => date('Y-m-d H:i:s')
];
$logId = $this->syncLog->create($logData);
// Start sync in background
$this->startBackgroundSync($sourceId, $logId, $type);
return $this->json($response, [
'success' => true,
'message' => 'Sync started',
'log_id' => $logId
]);
} catch (\Exception $e) {
return $this->json($response, [
'success' => false,
'message' => 'Error starting sync: ' . $e->getMessage()
], 500);
}
}
// Get sync status
public function status(Request $request, Response $response, array $args): Response
{
$logId = $args['log_id'] ?? null;
if (!$logId) {
return $this->json($response, [
'success' => false,
'message' => 'Log ID is required'
], 400);
}
$log = $this->syncLog->find($logId);
if (!$log) {
return $this->json($response, [
'success' => false,
'message' => 'Sync log not found'
], 404);
}
// Get detailed status from the sync service if available
$status = [
'status' => $log['status'],
'progress' => (int)($log['progress'] ?? 0),
'message' => $log['message'] ?? '',
'started_at' => $log['started_at'],
'completed_at' => $log['completed_at'] ?? null,
'total_items' => (int)($log['total_items'] ?? 0),
'processed_items' => (int)($log['processed_items'] ?? 0),
'new_items' => (int)($log['new_items'] ?? 0),
'updated_items' => (int)($log['updated_items'] ?? 0),
'deleted_items' => (int)($log['deleted_items'] ?? 0)
];
return $this->json($response, [
'success' => true,
'log' => $status
]);
}
// Cancel a running sync
public function cancel(Request $request, Response $response, array $args): Response
{
$logId = $args['log_id'] ?? null;
if (!$logId) {
return $this->json($response, [
'success' => false,
'message' => 'Log ID is required'
], 400);
}
try {
// Update the log status to cancelled
$this->syncLog->update($logId, [
'status' => 'cancelled',
'completed_at' => date('Y-m-d H:i:s'),
'message' => 'Sync cancelled by user'
]);
// TODO: Send a signal to the running process to cancel
return $this->json($response, [
'success' => true,
'message' => 'Sync cancelled'
]);
} catch (\Exception $e) {
return $this->json($response, [
'success' => false,
'message' => 'Error cancelling sync: ' . $e->getMessage()
], 500);
}
}
// Clear sync logs
public function clearLogs(Request $request, Response $response, array $args): Response
{
$type = $request->getParsedBody()['type'] ?? 'completed'; // completed, all
try {
if ($type === 'all') {
$this->syncLog->query('TRUNCATE TABLE sync_logs');
} else {
$this->syncLog->where('status', 'completed')->delete();
$this->syncLog->where('status', 'failed')->delete();
$this->syncLog->where('status', 'cancelled')->delete();
}
return $this->json($response, [
'success' => true,
'message' => 'Logs cleared successfully'
]);
} catch (\Exception $e) {
return $this->json($response, [
'success' => false,
'message' => 'Error clearing logs: ' . $e->getMessage()
], 500);
}
}
// Start background sync process
private function startBackgroundSync($sourceId, $logId, $type = 'full')
{
// This is a simplified example - you'll need to implement this based on your needs
$command = sprintf(
'php %s/console.php sync:start --log=%d --type=%s %s > /dev/null 2>&1 &',
dirname(__DIR__, 3), // Path to your project root
$logId,
escapeshellarg($type),
$sourceId ? '--source=' . $sourceId : ''
);
exec($command);
}
// Process sync (called from CLI)
public function processSync($sourceId, $logId, $type = 'full')
{
try {
$log = $this->syncLog->find($logId);
if (!$log) {
throw new \Exception('Sync log not found');
}
// Update log status to started
$this->syncLog->update($logId, [
'status' => 'in_progress',
'started_at' => date('Y-m-d H:i:s'),
'message' => 'Sync started'
]);
$source = null;
if ($sourceId) {
$source = $this->source->find($sourceId);
if (!$source) {
throw new \Exception('Source not found');
}
}
// Get the appropriate sync service
$service = $this->getSyncService($source ? $source['type'] : 'local');
// Start sync
$result = $service->sync($source, $type, function($progress, $message) use ($logId) {
// Update progress callback
$this->updateSyncProgress($logId, $progress, $message);
});
// Update log with final status
$this->syncLog->update($logId, [
'status' => $result['success'] ? 'completed' : 'failed',
'completed_at' => date('Y-m-d H:i:s'),
'message' => $result['message'] ?? 'Sync completed',
'total_items' => $result['total_items'] ?? 0,
'processed_items' => $result['processed_items'] ?? 0,
'new_items' => $result['new_items'] ?? 0,
'updated_items' => $result['updated_items'] ?? 0,
'deleted_items' => $result['deleted_items'] ?? 0,
'errors' => !empty($result['errors']) ? json_encode($result['errors']) : null
]);
return $result;
} catch (\Exception $e) {
// Update log with error
if (isset($logId) && $this->syncLog) {
$this->syncLog->update($logId, [
'status' => 'failed',
'completed_at' => date('Y-m-d H:i:s'),
'message' => 'Error: ' . $e->getMessage()
]);
}
throw $e;
}
}
// Update sync progress
private function updateSyncProgress($logId, $progress, $message = '')
{
$this->syncLog->update($logId, [
'progress' => $progress,
'message' => $message,
'updated_at' => date('Y-m-d H:i:s')
]);
}
// Get the appropriate sync service
private function getSyncService($type)
{
$type = strtolower($type);
if (!isset($this->syncServices[$type])) {
throw new \Exception("Unsupported source type: $type");
}
return $this->syncServices[$type];
}
}