feat(workspace): live synchronisation, verbindungsindikator, leere ordner persistenz und sperrkonfliktschutz
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m0s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m0s
This commit is contained in:
1 parent
35fd682fcd
commit
2f92e1f49a
4 files changed
+234
-14
No files matched your search
@@ -1019,6 +1019,8 @@ export function getOfflineQueue(): Thought[] {
|
||||
let activeGlobalWS: WebSocket | null = null;
|
||||
let wsReconnectTimer: any = null;
|
||||
let wsListeners: ((msg: WSMessage) => void)[] = [];
|
||||
let wsStatusListeners: ((connected: boolean) => void)[] = [];
|
||||
let isWSConnected = false;
|
||||
let manualDisconnect = false;
|
||||
|
||||
export function buildWebSocketURL(listId?: string): string {
|
||||
@@ -1030,6 +1032,30 @@ export function buildWebSocketURL(listId?: string): string {
|
||||
return `${protocol}//${window.location.host}/api/v1/ws?token=${encodeURIComponent(token)}`;
|
||||
}
|
||||
|
||||
export function isWebSocketConnected(): boolean {
|
||||
return isWSConnected && activeGlobalWS !== null && activeGlobalWS.readyState === WebSocket.OPEN;
|
||||
}
|
||||
|
||||
export function onWebSocketStatus(callback: (connected: boolean) => void): () => void {
|
||||
wsStatusListeners.push(callback);
|
||||
callback(isWebSocketConnected());
|
||||
return () => {
|
||||
wsStatusListeners = wsStatusListeners.filter((fn) => fn !== callback);
|
||||
};
|
||||
}
|
||||
|
||||
function notifyStatusChange(connected: boolean) {
|
||||
isWSConnected = connected;
|
||||
wsStatusListeners.forEach((fn) => {
|
||||
try {
|
||||
fn(connected);
|
||||
} catch (e) {
|
||||
console.error('WS status listener error', e);
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(new CustomEvent('mindsift:ws:status', { detail: { connected } }));
|
||||
}
|
||||
|
||||
export function connectWebSocket(): void {
|
||||
const token = getToken();
|
||||
if (!token) return;
|
||||
@@ -1044,6 +1070,10 @@ export function connectWebSocket(): void {
|
||||
const ws = new WebSocket(url);
|
||||
activeGlobalWS = ws;
|
||||
|
||||
ws.onopen = () => {
|
||||
notifyStatusChange(true);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const msg = JSON.parse(event.data) as WSMessage;
|
||||
@@ -1062,6 +1092,7 @@ export function connectWebSocket(): void {
|
||||
|
||||
ws.onclose = () => {
|
||||
activeGlobalWS = null;
|
||||
notifyStatusChange(false);
|
||||
if (!manualDisconnect && getToken()) {
|
||||
clearTimeout(wsReconnectTimer);
|
||||
wsReconnectTimer = setTimeout(() => {
|
||||
@@ -1071,15 +1102,31 @@ export function connectWebSocket(): void {
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
notifyStatusChange(false);
|
||||
try {
|
||||
ws.close();
|
||||
} catch {}
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('Failed to connect WebSocket', e);
|
||||
notifyStatusChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure reconnect when browser recovers from sleep or tab visibility
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('online', () => {
|
||||
if (getToken() && !isWebSocketConnected()) {
|
||||
connectWebSocket();
|
||||
}
|
||||
});
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible' && getToken() && !isWebSocketConnected()) {
|
||||
connectWebSocket();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function disconnectWebSocket(): void {
|
||||
manualDisconnect = true;
|
||||
clearTimeout(wsReconnectTimer);
|
||||
@@ -1089,6 +1136,7 @@ export function disconnectWebSocket(): void {
|
||||
} catch {}
|
||||
activeGlobalWS = null;
|
||||
}
|
||||
notifyStatusChange(false);
|
||||
}
|
||||
|
||||
export function sendWebSocketMessage(msg: any): void {
|
||||
|
||||
Reference in new issue
Block a user