feat: OnlyOffice Standalone integration with S3 direct URLs

 ЧТО СДЕЛАНО:
- Поднят новый standalone OnlyOffice Document Server (порт 8083)
- Настроен Nginx для доступа через office.clientright.ru:9443
- Создан open_file_v3_standalone.php для работы с новым OnlyOffice
- Реализована поддержка прямых S3 URL (bucket публичный)
- Добавлен s3_proxy.php с поддержкой Range requests
- Создан onlyoffice_callback.php для сохранения (базовая версия)
- Файлы успешно открываются и загружаются!

⚠️ TODO (на завтра):
- Доработать onlyoffice_callback.php для сохранения обратно в ОРИГИНАЛЬНЫЙ путь в S3
- Добавить Redis маппинг documentKey → S3 path
- Обновить CRM JS для использования open_file_v3_standalone.php
- Протестировать сохранение файлов
- Удалить тестовые файлы

📊 РЕЗУЛЬТАТ:
- OnlyOffice Standalone РАБОТАЕТ! 
- Файлы открываются напрямую из S3 
- Редактор загружается БЫСТРО 
- Автосохранение настроено  (но нужна доработка callback)
This commit is contained in:
Fedor
2025-11-01 01:02:03 +03:00
parent d7941ac862
commit 269c7ea216
4383 changed files with 282112 additions and 7731 deletions

View File

@@ -0,0 +1,123 @@
#!/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);
});