Skip to content

Commit

Permalink
Merge pull request #328 from AElfProject/feature/refactor-2.0.0-Block…
Browse files Browse the repository at this point in the history
…chain

feat: home data add signalr
  • Loading branch information
Peterbjx committed May 1, 2024
2 parents 4b8dfe7 + 0c9dd38 commit 0fcbef2
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 37 deletions.
61 changes: 61 additions & 0 deletions src/_hooks/useHomeSocket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useMemo, useState } from 'react';
import Socket from '@_socket';
import { IBlocksResponseItem, ITransactionsResponseItem, TChainID } from '@_api/type';
interface IIntervalData {
blocks: Array<IBlocksResponseItem>;
transactions: ITransactionsResponseItem[];
blocksLoading: boolean;
transactionsLoading: boolean;
}
const useHomeSocket = (chain: TChainID) => {
const [blocks, setBlocks] = useState<Array<IBlocksResponseItem>>([]);
const [transactions, setTransactions] = useState<ITransactionsResponseItem[]>([]);
const [blocksLoading, setBlocksLoading] = useState<boolean>(true);
const [transactionsLoading, setTransactionsLoading] = useState<boolean>(true);
console.log('signalR----------refresh');
const socket = Socket();

const data: IIntervalData = useMemo(() => {
// console.log('xxxxx', isCanBeBid, auctionInfo?.finishIdentifier);
return {
blocks,
blocksLoading,
transactionsLoading,
transactions,
};
}, [blocks, blocksLoading, transactions, transactionsLoading]);

useEffect(() => {
function fetchAndReceiveWs() {
if (!socket) {
return;
}

socket.registerHandler('ReceiveLatestBlocks', (data) => {
console.log('blocks---1', data);
setBlocks(data?.blocks || []);
setBlocksLoading(false);
});
socket.registerHandler('ReceiveLatestTransactions', (data) => {
setTransactions(data.transactions);
console.log('transactions---2', data);
setTransactionsLoading(false);
});
socket.sendEvent('RequestLatestTransactions', { chainId: chain });
socket.sendEvent('RequestLatestBlocks', { chainId: chain });
}

fetchAndReceiveWs();

return () => {
console.log('signalR----destroy');
socket?.destroy();
// socket?.sendEvent('UnSubscribeLatestTransactions');
// socket?.sendEvent('UnSubscribeLatestBlocks');
};
}, [chain, socket]);

return data;
};

export default useHomeSocket;
27 changes: 27 additions & 0 deletions src/_socket/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';
import SignalR from './signalr';

export default function Socket() {
// const [error, setError] = useState<any>(null);
const [socket, setSocket] = useState<SignalR | null>(null);
const pathName = usePathname();
useEffect(() => {
const signalR = new SignalR({ url: '/api/app/blockchain/explore' });
console.log('signalR---', signalR);
// if (error !== false) {
signalR
.initAndStart()
.then(() => {
setSocket(signalR);
// setError(false);
})
.catch((e) => {
setSocket(signalR);
// setError(e);
});
// }
}, [pathName]);

return socket;
}
124 changes: 124 additions & 0 deletions src/_socket/signalr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { HubConnection, HubConnectionBuilder, HttpTransportType } from '@microsoft/signalr';
// import { IBidInfo, IBidInfosResponse } from './types';

type SignalRParams = {
url: string;
};

// type ReceiveDataType = IBidInfo | IBidInfosResponse;

type HandlerFn = (data: any) => void;

const messageType: Array<string> = ['ReceiveLatestTransactions', 'ReceiveLatestBlocks'];

export default class SignalR {
private connection: HubConnection | null;
private url: string;
private handlerMap: Map<string, Array<HandlerFn>>;

constructor({ url }: SignalRParams) {
this.url = url;
this.connection = new HubConnectionBuilder()
.withUrl(this.url, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
})
.withAutomaticReconnect()
.build();
this.handlerMap = new Map();
}

initAndStart = () => {
this.connection?.onclose((err) => {
console.log('signalR---onclose', err);
});
console.log('signalR---initAndStart');
this.listen();

return new Promise((resolve, reject) => {
this.connection
?.start()
.then(() => {
resolve(this.connection);
})
.catch((e) => {
reject(e);
});
});
};

listen = () => {
try {
messageType.length &&
messageType.forEach((name) => {
this.connection?.on(name, (data) => {
this.dispatchMessage(name, data);
});
});
} catch (err) {
console.log('listen err', err);
}
};

registerHandler = (message: string, handler: HandlerFn) => {
try {
const handlers = this.handlerMap.get(message);
if (handlers) {
this.handlerMap.set(message, [...handlers, handler]);
} else {
this.handlerMap.set(message, [handler]);
}
} catch (err) {
console.log('registerHandler err', err);
}
};

unRegisterHandler = (message: string, handler: HandlerFn) => {
try {
const handlers = this.handlerMap.get(message);
if (handlers) {
this.handlerMap.set(
message,
handlers.filter((fn) => fn !== handler),
);
}
} catch (err) {
console.log('unsubscribe err', err);
}
};

dispatchMessage = (message: string, data: any) => {
try {
const handlers = this.handlerMap.get(message);
handlers &&
handlers.forEach((handler) => {
handler(data);
});
} catch (err) {
console.log('dispatchMessage err', err);
}
};

sendEvent = (name: string, ...rest: any[]) => {
try {
if (rest.length === 0) {
this.connection?.invoke(name);
} else if (rest.length === 1) {
this.connection?.invoke(name, rest[0]);
} else if (rest.length === 2) {
this.connection?.invoke(name, rest[0], rest[1]);
} else if (rest.length === 3) {
this.connection?.invoke(name, rest[0], rest[1], rest[2]);
} else {
console.log('too much params');
}
} catch (err) {
console.log('subscribeEvent err', err);
}
};

destroy(): void {
// this.connection?.stop();
this.handlerMap.clear();
}
}
43 changes: 6 additions & 37 deletions src/pageComponents/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,23 @@ import InfoSection from './_components/InfoSection';
import SearchComp from './_components/SearchWithClient';
import clsx from 'clsx';
import './index.css';
import { useEffect, useState, useCallback } from 'react';
import { useEffect, useState } from 'react';
import { HubConnection, HubConnectionBuilder, HttpTransportType } from '@microsoft/signalr';
import { IOverviewSSR } from './type';
// import { MessagePackHubProtocol } from '@microsoft/signalr-protocol-msgpack';
import Latest from './_components/Latest';
import TPSChart from './_components/TPSChart';
import tpsData from './mock';
import useResponsive, { useMobileAll } from '@_hooks/useResponsive';
import { useMobileAll } from '@_hooks/useResponsive';
const BannerPc = '/image/banner_pc.png';
const BannerMobile = '/image/banner_mobile.png';
const clsPrefix = 'home-container';
import { useEnvContext } from 'next-runtime-env';
import { IBlocksResponseItem, ITransactionsResponseItem, TChainID } from '@_api/type';
import { fetchLatestBlocksList } from '@_api/fetchBlocks';
import { Spin } from 'antd';
import { fetchLatestTransactionList } from '@_api/fetchTransactions';
import { useAppSelector } from '@_store';
import { useSearchParams } from 'next/navigation';
import useHomeSocket from '@_hooks/useHomeSocket';
import { TChainID } from '@_api/type';

interface IProps {
overviewSSR: IOverviewSSR;
Expand All @@ -46,43 +45,13 @@ const getConnectionBuilder = (url: string) => {
};
export default function Home({ overviewSSR }: IProps) {
const { NEXT_PUBLIC_API_URL: HOST } = useEnvContext();
const [loading, setLoading] = useState<boolean>(false);
const [transactionsLoading, setTransactionsLoading] = useState<boolean>(false);
const [blocks, setBlocks] = useState<IBlocksResponseItem[]>([]);
const { defaultChain } = useAppSelector((state) => state.getChainId);
const searchParmas = useSearchParams();
const chain = searchParmas.get('chainId') || defaultChain;
const [transactions, setTransactions] = useState<ITransactionsResponseItem[]>([]);

const fetchBlocksData = useCallback(async () => {
setLoading(true);
try {
const data = await fetchLatestBlocksList({ chainId: chain as TChainID });
console.log(data, 'data');
setLoading(false);
setBlocks(data.blocks);
} catch (error) {
setLoading(false);
}
}, [chain]);

const fetchTransactionData = useCallback(async () => {
setTransactionsLoading(true);
try {
const data = await fetchLatestTransactionList({ chainId: chain as TChainID, maxResultCount: 25 });
console.log(data, 'data');
setTransactionsLoading(false);
setTransactions(data.transactions);
} catch (error) {
setTransactionsLoading(false);
}
}, [chain]);
const { blocks, blocksLoading, transactionsLoading, transactions } = useHomeSocket(chain as TChainID);

const isMobile = useMobileAll();
useEffect(() => {
fetchBlocksData();
fetchTransactionData();
}, []);

const OverView: React.FC = () => {
const [connection, setConnection] = useState<null | HubConnection>(null);
Expand Down Expand Up @@ -130,7 +99,7 @@ export default function Home({ overviewSSR }: IProps) {
return (
<div className={clsx('latest-all', isMobile && 'latest-all-mobile')}>
<div className="flex-1">
<Spin spinning={loading}>
<Spin spinning={blocksLoading}>
<Latest iconType="latest-block" isBlocks={true} data={blocks} isMobile={isMobile}></Latest>
</Spin>
</div>
Expand Down

0 comments on commit 0fcbef2

Please sign in to comment.