Files
ai-showcase-platform/lib/client-connection-cleanup.ts

232 lines
6.2 KiB
TypeScript
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.

// =====================================================
// 客戶端連線清理腳本
// =====================================================
export class ClientConnectionCleanup {
private static instance: ClientConnectionCleanup;
private isCleaning = false;
private clientId: string;
private constructor() {
this.clientId = this.generateClientId();
this.setupEventListeners();
}
public static getInstance(): ClientConnectionCleanup {
if (!ClientConnectionCleanup.instance) {
ClientConnectionCleanup.instance = new ClientConnectionCleanup();
}
return ClientConnectionCleanup.instance;
}
// 生成客戶端唯一標識符
private generateClientId(): string {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2);
return `client_${timestamp}_${random}`;
}
// 設置事件監聽器
private setupEventListeners() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') {
console.log('🖥️ 客戶端連線清理跳過(服務端環境)');
return;
}
// 頁面關閉前清理
window.addEventListener('beforeunload', () => {
this.cleanupOnUnload();
});
// 頁面隱藏時清理
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.cleanupOnHidden();
}
});
// 頁面卸載時清理
window.addEventListener('unload', () => {
this.cleanupOnUnload();
});
// 定期清理每5分鐘
setInterval(() => {
this.periodicCleanup();
}, 5 * 60 * 1000);
console.log('🖥️ 客戶端連線清理已啟動');
}
// 頁面關閉前清理
private async cleanupOnUnload() {
if (this.isCleaning) return;
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
this.isCleaning = true;
console.log('🔄 頁面關閉前清理連線...');
try {
// 使用 sendBeacon 確保請求能夠發送
const data = JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
timestamp: Date.now()
});
// 嘗試使用 sendBeacon
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/ip-cleanup', data);
console.log('✅ 使用 sendBeacon 發送清理請求');
} else {
// 備用方案:使用 fetch
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: data,
keepalive: true
});
console.log('✅ 使用 fetch 發送清理請求');
}
} catch (error) {
console.error('❌ 清理請求發送失敗:', error);
}
}
// 頁面隱藏時清理
private async cleanupOnHidden() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
console.log('🔄 頁面隱藏時清理連線...');
try {
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
reason: 'page-hidden'
})
});
console.log('✅ 頁面隱藏清理完成');
} catch (error) {
console.error('❌ 頁面隱藏清理失敗:', error);
}
}
// 定期清理
private async periodicCleanup() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
console.log('🔄 定期清理連線...');
try {
const response = await fetch('/api/ip-cleanup?action=local-stats');
const data = await response.json();
if (data.success && data.data.trackedConnections > 10) {
// 如果追蹤的連線數超過10個執行清理
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-local',
clientId: this.clientId,
reason: 'periodic-cleanup'
})
});
console.log('✅ 定期清理完成');
}
} catch (error) {
console.error('❌ 定期清理失敗:', error);
}
}
// 手動清理
public async manualCleanup(): Promise<boolean> {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return false;
try {
const response = await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
reason: 'manual-cleanup'
})
});
const data = await response.json();
if (data.success) {
console.log('✅ 手動清理完成:', data.message);
return true;
} else {
console.error('❌ 手動清理失敗:', data.error);
return false;
}
} catch (error) {
console.error('❌ 手動清理錯誤:', error);
return false;
}
}
// 獲取連線狀態
public async getConnectionStatus() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return null;
try {
const response = await fetch('/api/ip-cleanup?action=status');
const data = await response.json();
if (data.success) {
console.log('📊 連線狀態:', data.data);
return data.data;
} else {
console.error('❌ 獲取連線狀態失敗:', data.error);
return null;
}
} catch (error) {
console.error('❌ 獲取連線狀態錯誤:', error);
return null;
}
}
// 獲取客戶端 ID
public getClientId(): string {
return this.clientId;
}
}
// 導出單例實例
export const clientCleanup = ClientConnectionCleanup.getInstance();
// 在模組載入時自動初始化(只在瀏覽器環境中)
if (typeof window !== 'undefined') {
// 延遲初始化,確保 DOM 已載入
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
clientCleanup;
});
} else {
clientCleanup;
}
}