Updates
This commit is contained in:
@@ -6,7 +6,7 @@ type Params = {
|
||||
|
||||
let timeout: any;
|
||||
|
||||
export default function twuiUseReady(params?: Params) {
|
||||
export default function useReady(params?: Params) {
|
||||
const [ready, setReady] = React.useState(false);
|
||||
|
||||
const finalTimeout = params?.timeout || 300;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
|
||||
type Params = {
|
||||
initialLoading?: boolean;
|
||||
initialReady?: boolean;
|
||||
};
|
||||
|
||||
export type UseStatusStatusType = {
|
||||
msg?: string;
|
||||
error?: boolean;
|
||||
};
|
||||
|
||||
export default function useStatus(params?: Params) {
|
||||
const [refresh, setRefresh] = React.useState(0);
|
||||
const [loading, setLoading] = React.useState(
|
||||
params?.initialLoading || false
|
||||
);
|
||||
const [status, setStatus] = React.useState<UseStatusStatusType>({});
|
||||
const [ready, setReady] = React.useState(params?.initialReady || false);
|
||||
|
||||
return {
|
||||
refresh,
|
||||
setRefresh,
|
||||
loading,
|
||||
setLoading,
|
||||
status,
|
||||
setStatus,
|
||||
ready,
|
||||
setReady,
|
||||
};
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
import React from "react";
|
||||
import React, { useRef } from "react";
|
||||
|
||||
export type UseWebsocketHookParams = {
|
||||
debounce?: number;
|
||||
url: string;
|
||||
disableReconnect?: boolean;
|
||||
/** Interval to ping the websocket. So that the connection doesn't go down. Default 30000ms (30 seconds) */
|
||||
keepAliveDuration?: number;
|
||||
refreshConnection?: number;
|
||||
};
|
||||
|
||||
export const WebSocketEventNames = ["wsDataEvent", "wsMessageEvent"] as const;
|
||||
|
||||
let tries = 0;
|
||||
|
||||
/**
|
||||
* # Use Websocket Hook
|
||||
* @event wsDataEvent Listen for event named `wsDataEvent` on `window` to receive Data events
|
||||
@@ -33,18 +32,20 @@ export default function useWebSocket<
|
||||
keepAliveDuration,
|
||||
refreshConnection,
|
||||
}: UseWebsocketHookParams) {
|
||||
const DEBOUNCE = debounce || 200;
|
||||
const DEBOUNCE = debounce || 500;
|
||||
const KEEP_ALIVE_DURATION = keepAliveDuration || 1000 * 30;
|
||||
const KEEP_ALIVE_TIMEOUT = 1000 * 60 * 3;
|
||||
|
||||
const KEEP_ALIVE_MESSAGE = "twui::ping";
|
||||
|
||||
let uptime = 0;
|
||||
let tries = useRef(0);
|
||||
|
||||
let reconnectInterval: any;
|
||||
let msgInterval: any;
|
||||
let sendInterval: any;
|
||||
let keepAliveInterval: any;
|
||||
// const queue: string[] = [];
|
||||
|
||||
const msgInterval = useRef<any>(null);
|
||||
const sendInterval = useRef<any>(null);
|
||||
const keepAliveInterval = useRef<any>(null);
|
||||
|
||||
const [socket, setSocket] = React.useState<WebSocket | undefined>(
|
||||
undefined
|
||||
@@ -77,141 +78,94 @@ export default function useWebSocket<
|
||||
const wsURL = url.startsWith(`ws`)
|
||||
? url
|
||||
: domain.replace(/^http/, "ws") + ("/" + url).replace(/\/\//g, "/");
|
||||
|
||||
if (!wsURL) return;
|
||||
|
||||
let ws = new WebSocket(wsURL);
|
||||
|
||||
ws.onopen = (ev) => {
|
||||
window.clearInterval(reconnectInterval);
|
||||
window.clearInterval(keepAliveInterval);
|
||||
keepAliveInterval = setInterval(() => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(KEEP_ALIVE_MESSAGE);
|
||||
uptime += KEEP_ALIVE_DURATION;
|
||||
if (uptime >= KEEP_ALIVE_TIMEOUT) {
|
||||
console.log("Websocket connection timed out ...");
|
||||
window.clearInterval(keepAliveInterval);
|
||||
ws.close();
|
||||
}
|
||||
}
|
||||
}, KEEP_ALIVE_DURATION);
|
||||
setSocket(ws);
|
||||
tries = 0;
|
||||
console.log(`Websocket connected to ${wsURL}`);
|
||||
uptime = 0;
|
||||
ws.onerror = (ev) => {
|
||||
console.log(`Websocket ERROR:`);
|
||||
};
|
||||
|
||||
ws.onmessage = (ev) => {
|
||||
window.clearInterval(msgInterval);
|
||||
messageQueueRef.current.push(ev.data);
|
||||
msgInterval = setInterval(handleReceivedMessageQueue, DEBOUNCE);
|
||||
if (ev.data !== KEEP_ALIVE_MESSAGE) {
|
||||
uptime = 0;
|
||||
}
|
||||
};
|
||||
|
||||
ws.onopen = (ev) => {
|
||||
window.clearInterval(keepAliveInterval.current);
|
||||
|
||||
keepAliveInterval.current = window.setInterval(() => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(KEEP_ALIVE_MESSAGE);
|
||||
}
|
||||
}, KEEP_ALIVE_DURATION);
|
||||
|
||||
setSocket(ws);
|
||||
console.log(`Websocket connected to ${wsURL}`);
|
||||
};
|
||||
|
||||
ws.onclose = (ev) => {
|
||||
console.log("Websocket closed!");
|
||||
console.log("Websocket closed!", {
|
||||
code: ev.code,
|
||||
reason: ev.reason,
|
||||
wasClean: ev.wasClean,
|
||||
});
|
||||
|
||||
if (disableReconnect) return;
|
||||
|
||||
console.log("Attempting to reconnect ...");
|
||||
console.log("URL:", url);
|
||||
window.clearInterval(keepAliveInterval);
|
||||
window.clearInterval(keepAliveInterval.current);
|
||||
|
||||
reconnectInterval = setInterval(() => {
|
||||
if (tries >= 3) {
|
||||
return window.clearInterval(reconnectInterval);
|
||||
}
|
||||
console.log("tries", tries);
|
||||
|
||||
console.log("Attempting to reconnect ...");
|
||||
tries++;
|
||||
if (tries.current >= 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect();
|
||||
}, 1000);
|
||||
console.log("Attempting to reconnect ...");
|
||||
|
||||
tries.current += 1;
|
||||
|
||||
connect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* # Window Close Handler
|
||||
*/
|
||||
const handleWindowClose = React.useCallback(() => {
|
||||
console.log("Window Unloaded ...");
|
||||
}, [socket]);
|
||||
|
||||
/**
|
||||
* # Window Focus Handler
|
||||
*/
|
||||
const handleWindowFocus = React.useCallback(() => {
|
||||
if (socket?.readyState === WebSocket.CLOSED) {
|
||||
console.log("Websocket closed ... Attempting to reconnect ...");
|
||||
connect();
|
||||
}
|
||||
if (socket?.readyState === WebSocket.OPEN) {
|
||||
console.log("Websocket connection alive ...");
|
||||
socket.send(KEEP_ALIVE_MESSAGE);
|
||||
uptime = 0;
|
||||
}
|
||||
}, [socket]);
|
||||
|
||||
/**
|
||||
* # Initial Connection
|
||||
*/
|
||||
React.useEffect(() => {
|
||||
connect();
|
||||
if (socket) return;
|
||||
|
||||
return function () {
|
||||
window.clearInterval(reconnectInterval);
|
||||
};
|
||||
connect();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* # Window Close and Focus Handlers
|
||||
*/
|
||||
React.useEffect(() => {
|
||||
if (!socket) return;
|
||||
|
||||
window.addEventListener("beforeunload", handleWindowClose, {
|
||||
once: true,
|
||||
});
|
||||
window.addEventListener("focus", handleWindowFocus);
|
||||
sendInterval.current = setInterval(handleSendMessageQueue, DEBOUNCE);
|
||||
msgInterval.current = setInterval(handleReceivedMessageQueue, DEBOUNCE);
|
||||
|
||||
return function () {
|
||||
window.removeEventListener("focus", handleWindowFocus);
|
||||
window.removeEventListener("beforeunload", handleWindowClose);
|
||||
window.clearInterval(sendInterval.current);
|
||||
window.clearInterval(msgInterval.current);
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
/**
|
||||
* # Refresh Connection
|
||||
*/
|
||||
React.useEffect(() => {
|
||||
console.log("Refreshing connection ...");
|
||||
|
||||
if (!socket) return;
|
||||
if (socket.readyState !== WebSocket.CLOSED) {
|
||||
socket?.close();
|
||||
}
|
||||
connect();
|
||||
}, [refreshConnection]);
|
||||
|
||||
/**
|
||||
* Received Message Queue Handler
|
||||
*/
|
||||
const handleReceivedMessageQueue = React.useCallback(() => {
|
||||
if (messageQueueRef.current.length > 0) {
|
||||
const newMessage = messageQueueRef.current.shift();
|
||||
if (!newMessage) return;
|
||||
try {
|
||||
const jsonData = JSON.parse(newMessage);
|
||||
dispatchCustomEvent("wsMessageEvent", newMessage);
|
||||
dispatchCustomEvent("wsDataEvent", jsonData);
|
||||
} catch (error) {
|
||||
console.log("Unable to parse string. Returning string.");
|
||||
}
|
||||
} else {
|
||||
window.clearInterval(msgInterval);
|
||||
uptime = 0;
|
||||
try {
|
||||
const msg = messageQueueRef.current.shift();
|
||||
|
||||
if (!msg) return;
|
||||
|
||||
const jsonData = JSON.parse(msg);
|
||||
dispatchCustomEvent("wsMessageEvent", msg);
|
||||
dispatchCustomEvent("wsDataEvent", jsonData);
|
||||
} catch (error) {
|
||||
console.log("Unable to parse string. Returning string.");
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -219,13 +173,15 @@ export default function useWebSocket<
|
||||
* Send Message Queue Handler
|
||||
*/
|
||||
const handleSendMessageQueue = React.useCallback(() => {
|
||||
if (sendMessageQueueRef.current.length > 0) {
|
||||
const newMessage = sendMessageQueueRef.current.shift();
|
||||
if (!newMessage) return;
|
||||
socket?.send(newMessage);
|
||||
} else {
|
||||
window.clearInterval(sendInterval);
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
window.clearInterval(sendInterval.current);
|
||||
return;
|
||||
}
|
||||
|
||||
const newMessage = sendMessageQueueRef.current.shift();
|
||||
if (!newMessage) return;
|
||||
|
||||
socket.send(newMessage);
|
||||
}, [socket]);
|
||||
|
||||
/**
|
||||
@@ -234,9 +190,14 @@ export default function useWebSocket<
|
||||
const sendData = React.useCallback(
|
||||
(data: T) => {
|
||||
try {
|
||||
window.clearInterval(sendInterval);
|
||||
sendMessageQueueRef.current.push(JSON.stringify(data));
|
||||
sendInterval = setInterval(handleSendMessageQueue, DEBOUNCE);
|
||||
const queueItemJSON = JSON.stringify(data);
|
||||
|
||||
const existingQueue = sendMessageQueueRef.current.find(
|
||||
(q) => q == queueItemJSON
|
||||
);
|
||||
if (!existingQueue) {
|
||||
sendMessageQueueRef.current.push(queueItemJSON);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log("Error Sending socket message", error.message);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export default function useWindowFocus() {
|
||||
const [isWindowFocused, setIsWindowFocused] = useState(false);
|
||||
|
||||
const windowFocusCb = useCallback(() => {
|
||||
setIsWindowFocused(true);
|
||||
}, []);
|
||||
|
||||
const windowBlurCb = useCallback(() => {
|
||||
setIsWindowFocused(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("focus", windowFocusCb);
|
||||
window.addEventListener("blur", windowBlurCb);
|
||||
return function () {
|
||||
window.removeEventListener("focus", windowFocusCb);
|
||||
window.removeEventListener("blur", windowBlurCb);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { isWindowFocused };
|
||||
}
|
||||
Reference in New Issue
Block a user