87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
|
|
import { Injectable, signal } from '@angular/core';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Service for automatic page reload when server restarts.
|
||
|
|
* Connects to WebSocket endpoint and monitors server instance ID.
|
||
|
|
* When server restarts with new ID, page automatically reloads.
|
||
|
|
*/
|
||
|
|
@Injectable({ providedIn: 'root' })
|
||
|
|
export class ReloadService {
|
||
|
|
private ws: WebSocket | null = null;
|
||
|
|
private instanceId = signal<string | null>(null);
|
||
|
|
private reconnectAttempts = 0;
|
||
|
|
private maxReconnectAttempts = 10;
|
||
|
|
private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
|
||
|
|
|
||
|
|
constructor() {
|
||
|
|
this.connect();
|
||
|
|
}
|
||
|
|
|
||
|
|
private connect(): void {
|
||
|
|
// Clean up any existing connection
|
||
|
|
if (this.ws) {
|
||
|
|
this.ws.close();
|
||
|
|
this.ws = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||
|
|
const wsUrl = `${protocol}//${location.host}/ws/reload`;
|
||
|
|
|
||
|
|
try {
|
||
|
|
this.ws = new WebSocket(wsUrl);
|
||
|
|
|
||
|
|
this.ws.onopen = () => {
|
||
|
|
console.log('[ReloadService] Connected to server');
|
||
|
|
this.reconnectAttempts = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
this.ws.onmessage = (event) => {
|
||
|
|
try {
|
||
|
|
const data = JSON.parse(event.data);
|
||
|
|
if (data.type === 'instance') {
|
||
|
|
const currentId = this.instanceId();
|
||
|
|
if (currentId !== null && currentId !== data.id) {
|
||
|
|
// Server restarted with new ID - reload page
|
||
|
|
console.log('[ReloadService] Server restarted, reloading...');
|
||
|
|
location.reload();
|
||
|
|
} else {
|
||
|
|
console.log(`[ReloadService] Instance ID: ${data.id}`);
|
||
|
|
}
|
||
|
|
this.instanceId.set(data.id);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error('[ReloadService] Failed to parse message:', e);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
this.ws.onclose = () => {
|
||
|
|
console.log('[ReloadService] Connection closed');
|
||
|
|
this.scheduleReconnect();
|
||
|
|
};
|
||
|
|
|
||
|
|
this.ws.onerror = (error) => {
|
||
|
|
console.error('[ReloadService] WebSocket error:', error);
|
||
|
|
this.ws?.close();
|
||
|
|
};
|
||
|
|
} catch (e) {
|
||
|
|
console.error('[ReloadService] Failed to create WebSocket:', e);
|
||
|
|
this.scheduleReconnect();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private scheduleReconnect(): void {
|
||
|
|
if (this.reconnectTimeout) {
|
||
|
|
clearTimeout(this.reconnectTimeout);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||
|
|
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 10000);
|
||
|
|
this.reconnectAttempts++;
|
||
|
|
console.log(`[ReloadService] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
|
||
|
|
this.reconnectTimeout = setTimeout(() => this.connect(), delay);
|
||
|
|
} else {
|
||
|
|
console.log('[ReloadService] Max reconnect attempts reached');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|