Files
crm.clientright.ru/crm_extensions/file_storage/test_redis.html
Fedor 9245768987 🚀 CRM Files Migration & Real-time Features
 Features:
- Migrated ALL files to new S3 structure (Projects, Contacts, Accounts, HelpDesk, Invoice, etc.)
- Added Nextcloud folder buttons to ALL modules
- Fixed Nextcloud editor integration
- WebSocket server for real-time updates
- Redis Pub/Sub integration
- File path manager for organized storage
- Redis caching for performance (Functions.php)

📁 New Structure:
Documents/Project/ProjectName_ID/file_docID.ext
Documents/Contacts/FirstName_LastName_ID/file_docID.ext
Documents/Accounts/AccountName_ID/file_docID.ext

🔧 Technical:
- FilePathManager for standardized paths
- S3StorageService integration
- WebSocket server (Node.js + Docker)
- Redis cache for getBasicModuleInfo()
- Predis library for Redis connectivity

📝 Scripts:
- Migration scripts for all modules
- Test pages for WebSocket/SSE/Polling
- Documentation (MIGRATION_*.md, REDIS_*.md)

🎯 Result: 15,000+ files migrated successfully!
2025-10-24 19:59:28 +03:00

213 lines
8.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>🚀 Redis Pub/Sub Test</title>
<style>
body { font-family: Arial; max-width: 1200px; margin: 40px auto; padding: 20px; background: #f5f5f5; }
.panel { background: white; padding: 30px; margin-bottom: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { color: #333; border-bottom: 3px solid #667eea; padding-bottom: 10px; }
.status { padding: 15px; margin: 20px 0; font-size: 16px; border-radius: 8px; }
.status.success { background: #d4edda; border-left: 4px solid #28a745; }
.status.error { background: #f8d7da; border-left: 4px solid #dc3545; }
.status.info { background: #d1ecf1; border-left: 4px solid #17a2b8; }
button { padding: 12px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; margin: 5px; background: #667eea; color: white; font-weight: 600; }
button:hover { background: #5568d3; }
.log-container { background: #1e1e1e; color: #d4d4d4; padding: 20px; border-radius: 6px; height: 400px; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 14px; }
.log-entry { margin-bottom: 5px; line-height: 1.6; }
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin: 20px 0; }
.stat-card { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px; text-align: center; }
.stat-value { font-size: 2em; font-weight: bold; }
.stat-label { font-size: 0.9em; opacity: 0.9; margin-top: 5px; }
</style>
</head>
<body>
<div class="panel">
<h1>🚀 Redis Pub/Sub + SSE Test</h1>
<div id="sseStatus" class="status info">
<strong>Подключение...</strong>
</div>
<div class="stats">
<div class="stat-card">
<div class="stat-value" id="eventCount">0</div>
<div class="stat-label">Событий</div>
</div>
<div class="stat-card">
<div class="stat-value" id="latency">-</div>
<div class="stat-label">Задержка</div>
</div>
<div class="stat-card">
<div class="stat-value" id="status">🔴</div>
<div class="stat-label">Статус</div>
</div>
</div>
<div>
<button onclick="testWebhook('file_created')">📝 Тест: Файл создан</button>
<button onclick="testWebhook('file_updated')">✏️ Тест: Файл обновлен</button>
<button onclick="testWebhook('file_deleted')">🗑️ Тест: Файл удален</button>
<button onclick="clearLog()">🧹 Очистить</button>
</div>
</div>
<div class="panel">
<h3>📝 Лог событий (мгновенная доставка через Redis!)</h3>
<div class="log-container" id="log">
Ожидание подключения...
</div>
</div>
<div class="panel">
<h3>⚡ Преимущества Redis Pub/Sub:</h3>
<ul>
<li><strong>Мгновенная доставка:</strong> &lt;100 мс (vs 5-9 сек Long Polling)</li>
<li><strong>Нет лишних запросов:</strong> постоянное SSE соединение</li>
<li><strong>Масштабируемость:</strong> тысячи клиентов одновременно</li>
<li><strong>Низкая нагрузка:</strong> события push, а не pull</li>
</ul>
</div>
<script>
let eventSource;
let eventCount = 0;
let webhookTime = null;
function log(message) {
const logContainer = document.getElementById('log');
const time = new Date().toLocaleTimeString('ru-RU');
const entry = document.createElement('div');
entry.className = 'log-entry';
entry.textContent = `[${time}] ${message}`;
logContainer.appendChild(entry);
logContainer.scrollTop = logContainer.scrollHeight;
}
function updateStatus(status, message) {
const statusEl = document.getElementById('sseStatus');
const statusIcon = document.getElementById('status');
switch(status) {
case 'connected':
statusEl.className = 'status success';
statusEl.innerHTML = '<strong>✅ ' + message + '</strong>';
statusIcon.textContent = '🟢';
break;
case 'disconnected':
statusEl.className = 'status error';
statusEl.innerHTML = '<strong>❌ ' + message + '</strong>';
statusIcon.textContent = '🔴';
break;
default:
statusEl.className = 'status info';
statusEl.innerHTML = '<strong>🟡 ' + message + '</strong>';
statusIcon.textContent = '🟡';
}
}
function connectSSE() {
log('🔄 Подключение к Redis SSE...');
updateStatus('connecting', 'Подключение к Redis SSE...');
eventSource = new EventSource('/crm_extensions/file_storage/api/redis_sse.php');
eventSource.onopen = function() {
log('✅ SSE подключение установлено');
updateStatus('connected', 'Подключено к Redis через SSE');
};
eventSource.onmessage = function(event) {
try {
const data = JSON.parse(event.data);
handleEvent(data);
} catch (e) {
log('❌ Ошибка парсинга: ' + e.message);
}
};
eventSource.onerror = function(error) {
log('❌ Ошибка SSE: ' + error);
updateStatus('disconnected', 'Отключено от Redis');
// Переподключение через 5 сек
setTimeout(connectSSE, 5000);
};
}
function handleEvent(event) {
const type = event.type;
const data = event.data;
eventCount++;
document.getElementById('eventCount').textContent = eventCount;
// Вычисляем задержку
if (webhookTime) {
const latency = Date.now() - webhookTime;
document.getElementById('latency').textContent = latency + 'ms';
webhookTime = null;
}
switch(type) {
case 'connected':
log('🔗 ' + data.message);
break;
case 'file_created':
log(`📝 Файл создан: ${data.fileName} в ${data.module} (ID: ${data.recordId})`);
break;
case 'file_updated':
log(`✏️ Файл обновлен: ${data.fileName}`);
break;
case 'file_deleted':
log(`🗑️ Файл удален (ID: ${data.documentId})`);
break;
default:
log(`📨 Событие: ${type}`);
}
}
function testWebhook(type) {
log(`🧪 Отправка webhook: ${type}`);
webhookTime = Date.now();
const testData = {
action: type,
file_path: 'crm2/CRM_Active_Files/Documents/Project_123/test_file_456.pdf',
project_id: '123'
};
fetch('/crm_extensions/file_storage/api/nextcloud_webhook_redis.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(testData)
})
.then(response => response.json())
.then(data => {
log(`✅ Webhook ответ: ${data.message || data.status}`);
})
.catch(error => {
log(`❌ Ошибка webhook: ${error.message}`);
});
}
function clearLog() {
document.getElementById('log').innerHTML = 'Лог очищен...';
log('🧹 Лог очищен');
}
// Запуск при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
log('🚀 Страница загружена');
connectSSE();
});
</script>
</body>
</html>