#!/usr/bin/env node /** * Nextcloud Cache Updater * * Подписывается на Redis канал crm:file:events * При новом файле - обновляет кеш Nextcloud для этого файла * БЕЗ полного сканирования всей папки! */ const Redis = require('ioredis'); const { exec } = require('child_process'); const util = require('util'); const execPromise = util.promisify(exec); const CONFIG = { redis: { host: '147.45.146.17', port: 6379, password: 'CRM_Redis_Pass_2025_Secure!' }, channel: 'crm:file:events', nextcloudContainer: 'nextcloud-fresh' }; const redis = new Redis(CONFIG.redis); console.log('🔄 Nextcloud Cache Updater'); console.log('=========================================='); console.log(`📡 Подписка на: ${CONFIG.channel}`); console.log(`🐳 Nextcloud: ${CONFIG.nextcloudContainer}`); console.log(''); // Подписка на канал redis.subscribe(CONFIG.channel, (err, count) => { if (err) { console.error('❌ Ошибка подписки:', err); process.exit(1); } console.log(`✅ Подписка активна (${count} каналов)`); console.log('⏳ Ожидание событий...\n'); }); // Обработка событий redis.on('message', async (channel, message) => { try { const event = JSON.parse(message); // Логируем событие const timestamp = new Date().toISOString(); console.log(`[${timestamp}] 📥 Событие:`); console.log(` Type: ${event.type}`); console.log(` Source: ${event.source}`); console.log(` Path: ${event.path || event.filename}`); // Обрабатываем только создание/изменение файлов if (!['file_created', 'file_modified', 'file_update'].includes(event.type)) { console.log(` ⏭️ Пропуск (не файловое событие)\n`); return; } // Извлекаем путь файла let filePath = event.path || event.filename; // Для событий из S3 Monitor - путь уже правильный // Для событий из Nextcloud - может быть без префикса // Формируем путь для Nextcloud let ncPath = filePath; if (!ncPath.startsWith('/')) { ncPath = '/admin/files/crm/' + ncPath; } console.log(` 🔄 Обновление кеша Nextcloud...`); console.log(` Путь: ${ncPath}`); // Обновляем кеш только для этого файла const command = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${ncPath}" 2>&1`; try { const { stdout, stderr } = await execPromise(command); if (stderr && !stderr.includes('Starting scan')) { console.log(` ⚠️ Предупреждение: ${stderr}`); } console.log(` ✅ Кеш обновлён`); // Дополнительно очищаем statcache для этой папки const dirname = ncPath.substring(0, ncPath.lastIndexOf('/')); const clearCommand = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${dirname}" --shallow 2>&1`; await execPromise(clearCommand); console.log(` ✅ Родительская папка обновлена\n`); } catch (execError) { console.error(` ❌ Ошибка обновления: ${execError.message}\n`); } } catch (error) { console.error(`❌ Ошибка обработки события:`, error.message); console.error(` Сообщение:`, message.substring(0, 200)); console.log(''); } }); // Обработка ошибок redis.on('error', (err) => { console.error('❌ Redis ошибка:', err); }); // Graceful shutdown process.on('SIGINT', () => { console.log('\n\n🛑 Остановка...'); redis.disconnect(); process.exit(0); }); process.on('SIGTERM', () => { console.log('\n\n🛑 Остановка...'); redis.disconnect(); process.exit(0); });