Commit c5977740 authored by tom's avatar tom

rewrite to class

parent dc8dce68
...@@ -13,7 +13,7 @@ interface Params { ...@@ -13,7 +13,7 @@ interface Params {
type SocketData = [ null, null, string, string, Record<string, unknown> ]; type SocketData = [ null, null, string, string, Record<string, unknown> ];
interface SocketChannelSubscriber { interface SocketChannelSubscriber {
filters?: Array<string>; filters?: Array<string>;
callback: (payload: unknown) => void; onMessage: (payload: unknown) => void;
} }
export default function useApiSocket({ onOpen, onError, onClose }: Params) { export default function useApiSocket({ onOpen, onError, onClose }: Params) {
...@@ -82,7 +82,7 @@ export default function useApiSocket({ onOpen, onError, onClose }: Params) { ...@@ -82,7 +82,7 @@ export default function useApiSocket({ onOpen, onError, onClose }: Params) {
const subscribers = channels.current[channelId]; const subscribers = channels.current[channelId];
subscribers subscribers
?.filter((subscriber) => subscriber.filters ? subscriber.filters.includes(filterId) : true) ?.filter((subscriber) => subscriber.filters ? subscriber.filters.includes(filterId) : true)
?.forEach((subscriber) => subscriber.callback(payload)); ?.forEach((subscriber) => subscriber.onMessage(payload));
}); });
socket.current.addEventListener('error', (event) => { socket.current.addEventListener('error', (event) => {
......
import type { SocketData, SocketChannelSubscriber } from 'lib/socket/types';
import { SECOND } from 'lib/consts';
interface InitParams {
onOpen?: (event: Event) => void;
onError?: (event: Event) => void;
onClose?: (event: Event) => void;
}
const OPEN_STATE = 1;
class Socket {
private socket: WebSocket | undefined;
private heartBeatIntervalId: number | undefined;
private onReadyEvents: Array<SocketData> = [];
private channels: Record<string, Array<SocketChannelSubscriber>> = {};
init({ onOpen, onError, onClose }: InitParams) {
if (this.socket) {
return this;
}
// todo_tom pass host and base path from config
this.socket = new WebSocket('wss://blockscout.com/poa/core/socket/v2/websocket?vsn=2.0.0');
this.socket.addEventListener('open', (event: Event) => {
this.startHeartBeat();
onOpen?.(event);
this.onReadyEvents.forEach((data) => this.socket?.send(JSON.stringify(data)));
this.onReadyEvents = [];
});
this.socket.addEventListener('message', (event) => {
const data: SocketData = JSON.parse(event.data);
const channelId = data[2];
const filterId = data[3];
const payload = data[4];
const subscribers = this.channels[channelId];
subscribers
?.filter((subscriber) => subscriber.filters ? subscriber.filters.includes(filterId) : true)
?.forEach((subscriber) => subscriber.onMessage(payload));
});
this.socket.addEventListener('error', (event) => {
onError?.(event);
});
this.socket.addEventListener('close', (event) => {
onClose?.(event);
});
return this;
}
close() {
window.clearInterval(this.heartBeatIntervalId);
this.socket?.close();
this.socket = undefined;
this.onReadyEvents = [];
this.channels = {};
}
joinRoom(id: string, subscriber: SocketChannelSubscriber) {
const data: SocketData = [ null, null, id, 'phx_join', {} ];
if (this.socket?.readyState === OPEN_STATE) {
this.socket?.send(JSON.stringify(data));
} else {
this.onReadyEvents.push(data);
}
if (this.channels[id]) {
this.channels[id].push(subscriber);
} else {
this.channels[id] = [ subscriber ];
}
}
leaveRoom(id: string) {
// todo_tom remove only specified subscriber
const data: SocketData = [ null, null, id, 'phx_leave', {} ];
if (this.socket?.readyState === OPEN_STATE) {
this.socket?.send(JSON.stringify(data));
} else {
this.onReadyEvents.push(data);
}
this.channels[id] = [];
}
private startHeartBeat() {
this.heartBeatIntervalId = window.setInterval(() => {
const data: SocketData = [ null, null, 'phoenix', 'heartbeat', {} ];
this.socket?.send(JSON.stringify(data));
}, 30 * SECOND);
}
}
export default Socket;
export type SocketData = [ null, null, string, string, Record<string, unknown> ];
export interface SocketChannelSubscriber {
filters?: Array<string>;
onMessage: (payload: unknown) => void;
}
...@@ -5,8 +5,8 @@ import React from 'react'; ...@@ -5,8 +5,8 @@ import React from 'react';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import useApiSocket from 'lib/hooks/useApiSocket';
import useToast from 'lib/hooks/useToast'; import useToast from 'lib/hooks/useToast';
import Socket from 'lib/socket/Socket';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
...@@ -15,23 +15,24 @@ const Home = () => { ...@@ -15,23 +15,24 @@ const Home = () => {
const [ isFormVisible, setFormVisibility ] = React.useState(false); const [ isFormVisible, setFormVisibility ] = React.useState(false);
const [ token, setToken ] = React.useState(''); const [ token, setToken ] = React.useState('');
const { joinRoom, leaveRoom } = useApiSocket({});
React.useEffect(() => { React.useEffect(() => {
joinRoom('blocks:0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252', { const socket = (new Socket).init({});
socket.joinRoom('blocks:0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252', {
filters: [ 'new_block' ], filters: [ 'new_block' ],
callback: () => {}, onMessage: () => {},
}); });
return () => { return () => {
leaveRoom('blocks:0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252'); socket.leaveRoom('blocks:0xdc4765d9dabf6c6c4908fe97e649ef1f05cb6252');
socket.close();
}; };
}, [ joinRoom, leaveRoom ]); }, []);
React.useEffect(() => { React.useEffect(() => {
const token = cookies.get(cookies.NAMES.API_TOKEN); const token = cookies.get(cookies.NAMES.API_TOKEN);
setFormVisibility(Boolean(!token && appConfig.isAccountSupported)); setFormVisibility(Boolean(!token && appConfig.isAccountSupported));
}, [ joinRoom ]); }, []);
const checkSentry = React.useCallback(() => { const checkSentry = React.useCallback(() => {
Sentry.captureException(new Error('Test error'), { extra: { foo: 'bar' }, tags: { source: 'test' } }); Sentry.captureException(new Error('Test error'), { extra: { foo: 'bar' }, tags: { source: 'test' } });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment