77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
import ReconnectingWebSocket from 'reconnecting-websocket';
|
|
import { getAccessToken } from './storage';
|
|
|
|
type MessageHandler = (data: any) => void;
|
|
|
|
class WSClient {
|
|
private ws: ReconnectingWebSocket | null = null;
|
|
private handler = new Set<MessageHandler>();
|
|
|
|
/**
|
|
* Kết nối tới WebSocket server.
|
|
* @param url Địa chỉ WebSocket server (có thể là relative path như /mqtt)
|
|
* @param isAuthenticated Có sử dụng token xác thực hay không
|
|
*/
|
|
connect(url: string, isAuthenticated: boolean) {
|
|
if (this.ws) return;
|
|
let token = '';
|
|
if (isAuthenticated) {
|
|
token = getAccessToken();
|
|
}
|
|
let wsUrl = url;
|
|
if (url.startsWith('/')) {
|
|
// Relative path, prepend base WebSocket URL
|
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
wsUrl = `${protocol}//${window.location.host}${url}`;
|
|
}
|
|
wsUrl = isAuthenticated ? `${wsUrl}?token=${token}` : wsUrl;
|
|
this.ws = new ReconnectingWebSocket(wsUrl, [], {
|
|
maxRetries: 10,
|
|
maxReconnectionDelay: 10000,
|
|
});
|
|
this.ws.onmessage = (event) => {
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
this.handler.forEach((fn) => fn(data));
|
|
} catch (error) {
|
|
console.error('WS Parse Error: ', error);
|
|
}
|
|
};
|
|
}
|
|
/**
|
|
* Ngắt kết nối WebSocket và giải phóng tài nguyên.
|
|
*/
|
|
disconnect() {
|
|
this.ws?.close();
|
|
this.ws = null;
|
|
}
|
|
|
|
/**
|
|
* Gửi dữ liệu qua WebSocket.
|
|
* @param data Dữ liệu cần gửi (sẽ được stringify)
|
|
*/
|
|
send(data: any) {
|
|
this.ws?.send(JSON.stringify(data));
|
|
}
|
|
|
|
/**
|
|
* Đăng ký callback để nhận dữ liệu từ WebSocket.
|
|
* @param cb Hàm callback xử lý dữ liệu nhận được
|
|
* @returns Hàm hủy đăng ký callback
|
|
*/
|
|
subscribe(cb: MessageHandler) {
|
|
this.handler.add(cb);
|
|
return () => this.handler.delete(cb);
|
|
}
|
|
|
|
/**
|
|
* Kiểm tra trạng thái kết nối WebSocket.
|
|
* @returns true nếu đã kết nối, ngược lại là false
|
|
*/
|
|
isConnected() {
|
|
return this.ws?.readyState === WebSocket.OPEN;
|
|
}
|
|
}
|
|
|
|
export const wsClient = new WSClient();
|