- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
175 lines
4.9 KiB
JavaScript
175 lines
4.9 KiB
JavaScript
/**
|
|
* SSE Client - Server-Sent Events Manager
|
|
* Zero-Dependency EventSource wrapper with auto-reconnect
|
|
*/
|
|
class SSEManager {
|
|
constructor() {
|
|
this.connections = new Map();
|
|
}
|
|
|
|
/**
|
|
* Connect to SSE endpoint
|
|
* @param {string} url - SSE endpoint URL
|
|
* @param {Object} handlers - Event handlers
|
|
* @param {Function} [handlers.onOpen] - Connection opened callback
|
|
* @param {Function} [handlers.onError] - Error callback
|
|
* @param {Function} [handlers.onMessage] - Default message handler
|
|
* @param {Object} [handlers.events] - Named event handlers
|
|
* @returns {EventSource}
|
|
*/
|
|
connect(url, handlers = {}) {
|
|
// Close existing connection
|
|
this.disconnect(url);
|
|
|
|
const eventSource = new EventSource(url);
|
|
|
|
// Default handlers
|
|
eventSource.onopen = () => {
|
|
console.log('SSE connected:', url);
|
|
handlers.onOpen?.();
|
|
};
|
|
|
|
eventSource.onerror = (error) => {
|
|
console.error('SSE error:', error);
|
|
handlers.onError?.(error);
|
|
|
|
// Auto-reconnect after 5 seconds
|
|
setTimeout(() => {
|
|
console.log('SSE reconnecting:', url);
|
|
this.connect(url, handlers);
|
|
}, 5000);
|
|
};
|
|
|
|
// Custom event handlers
|
|
if (handlers.events) {
|
|
Object.entries(handlers.events).forEach(([event, handler]) => {
|
|
eventSource.addEventListener(event, (e) => {
|
|
try {
|
|
const data = JSON.parse(e.data);
|
|
handler(data, e);
|
|
} catch {
|
|
handler(e.data, e);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Default message handler
|
|
eventSource.onmessage = (e) => {
|
|
try {
|
|
const data = JSON.parse(e.data);
|
|
handlers.onMessage?.(data, e);
|
|
} catch {
|
|
handlers.onMessage?.(e.data, e);
|
|
}
|
|
};
|
|
|
|
this.connections.set(url, eventSource);
|
|
|
|
return eventSource;
|
|
}
|
|
|
|
/**
|
|
* Disconnect from SSE endpoint
|
|
* @param {string} url - SSE endpoint URL
|
|
*/
|
|
disconnect(url) {
|
|
const connection = this.connections.get(url);
|
|
if (connection) {
|
|
connection.close();
|
|
this.connections.delete(url);
|
|
console.log('SSE disconnected:', url);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disconnect all SSE connections
|
|
*/
|
|
disconnectAll() {
|
|
this.connections.forEach((conn, url) => {
|
|
conn.close();
|
|
console.log('SSE disconnected:', url);
|
|
});
|
|
this.connections.clear();
|
|
}
|
|
|
|
/**
|
|
* Check if connected to URL
|
|
* @param {string} url
|
|
* @returns {boolean}
|
|
*/
|
|
isConnected(url) {
|
|
return this.connections.has(url);
|
|
}
|
|
|
|
/**
|
|
* Get connection by URL
|
|
* @param {string} url
|
|
* @returns {EventSource|undefined}
|
|
*/
|
|
getConnection(url) {
|
|
return this.connections.get(url);
|
|
}
|
|
}
|
|
|
|
// Global instance
|
|
window.sseManager = new SSEManager();
|
|
|
|
// Cleanup on page unload
|
|
window.addEventListener('beforeunload', () => {
|
|
window.sseManager.disconnectAll();
|
|
});
|
|
|
|
/**
|
|
* Usage Examples:
|
|
*
|
|
* // 1. Notification Stream
|
|
* window.sseManager.connect('/notifications/stream', {
|
|
* events: {
|
|
* 'notification': (data) => {
|
|
* showNotification(data.message, data.type);
|
|
* },
|
|
* 'heartbeat': (data) => {
|
|
* console.log('Server alive:', data.status);
|
|
* }
|
|
* },
|
|
* onError: () => {
|
|
* console.log('Reconnecting to notifications...');
|
|
* }
|
|
* });
|
|
*
|
|
* // 2. Live Component Updates via SSE
|
|
* window.sseManager.connect('/live-component/UserCardComponent:123/stream', {
|
|
* events: {
|
|
* 'component-update': (data) => {
|
|
* const component = window.liveComponents.components.get('UserCardComponent:123');
|
|
* if (component) {
|
|
* component.element.innerHTML = data.html;
|
|
* component.state = JSON.parse(data.state);
|
|
* window.liveComponents.setupListeners(component.element, 'UserCardComponent:123');
|
|
* }
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* // 3. Job Progress Tracking
|
|
* function trackJobProgress(jobId) {
|
|
* const progressBar = document.getElementById('progress-bar');
|
|
* const progressText = document.getElementById('progress-text');
|
|
*
|
|
* window.sseManager.connect(`/jobs/${jobId}/progress`, {
|
|
* events: {
|
|
* 'progress': (data) => {
|
|
* progressBar.style.width = `${data.percentage}%`;
|
|
* progressText.textContent = data.message;
|
|
*
|
|
* if (data.status === 'completed') {
|
|
* window.sseManager.disconnect(`/jobs/${jobId}/progress`);
|
|
* alert('Job completed!');
|
|
* }
|
|
* }
|
|
* }
|
|
* });
|
|
* }
|
|
*/
|