From 3b4990865c04efb7350919ff575beba60d1a04c0 Mon Sep 17 00:00:00 2001 From: Marco van Dijk Date: Fri, 4 Mar 2022 14:46:39 +0100 Subject: [PATCH] Background loading enabled, moved out of specific components --- backend/src/routes/livepeer.js | 41 ++++----- src/App.js | 3 +- src/eventButton.js | 6 +- src/eventViewer.js | 3 + src/grafana.js | 2 + src/home.js | 157 ++++++++++++++------------------- src/livepeer.js | 31 ++----- src/loadingScreen.js | 87 +++++++++++------- src/reducers/root.js | 2 - src/store/store.js | 2 - 10 files changed, 159 insertions(+), 175 deletions(-) diff --git a/backend/src/routes/livepeer.js b/backend/src/routes/livepeer.js index c525fef..b7fa535 100644 --- a/backend/src/routes/livepeer.js +++ b/backend/src/routes/livepeer.js @@ -1,23 +1,27 @@ import express from "express"; import Event from '../models/event'; -const fs = require('fs'); const apiRouter = express.Router(); import { API_CMC, API_L1_HTTP, API_L2_HTTP, API_L2_WS } from "../config"; +// Do API requests to other API's const https = require('https'); +// Read ABI files +const fs = require('fs'); +// Used for the livepeer thegraph API import { request, gql } from 'graphql-request'; - -// Get ETH price & LPT coin prices +// Gets ETH, LPT and other coin info const CoinMarketCap = require('coinmarketcap-api'); const cmcClient = new CoinMarketCap(API_CMC); -// Get gas price on ETH (L2 already gets exported by the O's themselves) +// Gets blockchain data const { createAlchemyWeb3 } = require("@alch/alchemy-web3"); +// Gets gas prices const web3layer1 = createAlchemyWeb3(API_L1_HTTP); const web3layer2 = createAlchemyWeb3(API_L2_HTTP); +// For listening to blockchain events const web3layer2WS = createAlchemyWeb3(API_L2_WS); -// Update CMC related api calls every 5 minutes +// Update CoinMarketCap related api calls every 5 minutes const timeoutCMC = 300000; let cmcPriceGet = 0; let ethPrice = 0; @@ -25,7 +29,7 @@ let lptPrice = 0; let cmcQuotes = {}; let cmcCache = {}; -// Update alchemy related API calls every 2 seconds +// Update Alchemy related API calls every 2 seconds const timeoutAlchemy = 2000; let l2Gwei = 0; let l1Gwei = 0; @@ -34,10 +38,10 @@ let l1block = 0; let arbGet = 0; // Gas limits on common contract interactions +// 50000 gas for approval when creating a new O const redeemRewardGwei = 1053687; const claimTicketGwei = 1333043; const withdrawFeeGwei = 688913; -// 50000 gas for approval when creating a new O const stakeFeeGwei = 680000; const commissionFeeGwei = 140000; const serviceUriFee = 51000; @@ -94,7 +98,7 @@ var BondingManagerProxyListener = contractInstance.events.allEvents(async (error }); console.log("listening for events on", BondingManagerProxyAddr) -// Splits of the big CMC object into separate datas +// Splits of raw CMC object into coin quote data const parseCmc = async function () { try { cmcCache = await cmcClient.getTickers({ limit: 200 }); @@ -115,17 +119,7 @@ const parseCmc = async function () { } } - - - - - - - - - - -// Queries Alchemy for block info and fees +// Queries Alchemy for block info and gas fees const parseL1Blockchain = async function () { const l1Wei = await web3layer1.eth.getGasPrice(); l1block = await web3layer1.eth.getBlockNumber(); @@ -193,6 +187,7 @@ apiRouter.get("/grafana", async (req, res) => { } }); +// Exports raw CoinMarketCap info apiRouter.get("/cmc", async (req, res) => { try { const now = new Date().getTime(); @@ -207,6 +202,7 @@ apiRouter.get("/cmc", async (req, res) => { } }); +// Exports gas fees and contract prices apiRouter.get("/blockchains", async (req, res) => { try { const now = new Date().getTime(); @@ -240,7 +236,7 @@ apiRouter.get("/blockchains", async (req, res) => { } }); - +// Exports top 200 coin quotes apiRouter.get("/quotes", async (req, res) => { try { const now = new Date().getTime(); @@ -256,6 +252,7 @@ apiRouter.get("/quotes", async (req, res) => { } }); +// Exports list of smart contract events apiRouter.get("/getEvents", async (req, res) => { try { const now = new Date().getTime(); @@ -277,6 +274,7 @@ apiRouter.get("/getEvents", async (req, res) => { } }); +// Gets info on a given Orchestrator const parseOrchestrator = async function (reqAddr) { reqAddr = reqAddr.toLowerCase(); const now = new Date().getTime(); @@ -353,6 +351,7 @@ const parseOrchestrator = async function (reqAddr) { return orchestratorObj; } +// Exports info on a given Orchestrator apiRouter.get("/getOrchestrator", async (req, res) => { try { let reqOrch = req.query.orch; @@ -365,7 +364,6 @@ apiRouter.get("/getOrchestrator", async (req, res) => { res.status(400).send(err); } }); - apiRouter.get("/getOrchestrator/:orch", async (req, res) => { try { const reqObj = await parseOrchestrator(req.params.orch); @@ -374,7 +372,6 @@ apiRouter.get("/getOrchestrator/:orch", async (req, res) => { res.status(400).send(err); } }); - apiRouter.post("/getOrchestrator", async (req, res) => { try { const reqObj = await parseOrchestrator(req.body.orchAddr); diff --git a/src/App.js b/src/App.js index f0650ba..b504857 100644 --- a/src/App.js +++ b/src/App.js @@ -10,7 +10,6 @@ import { Route } from "react-router-dom"; - export default function App() { return ( @@ -30,4 +29,4 @@ export default function App() { ); -} +} \ No newline at end of file diff --git a/src/eventButton.js b/src/eventButton.js index 4b26a9a..1100d0a 100644 --- a/src/eventButton.js +++ b/src/eventButton.js @@ -2,7 +2,9 @@ import React from "react"; import { getOrchestratorInfo } from "./actions/livepeer"; -import { useDispatch } from 'react-redux' +import { useDispatch } from 'react-redux'; + +/// Displays a single event. Sets selected Orchestrator info in the redux store const activationColour = "rgba(23, 60, 122, 0.3)"; const rewardColour = "rgba(20, 99, 29, 0.3)"; @@ -29,7 +31,6 @@ const EventButton = (obj) => { let isOnlyBond = true; let thisColour = ""; - // Which we will fill in by going over all of the events once thisData.map(eventObj => { // Bond: contains amount the transaction is about and who is participating @@ -132,6 +133,7 @@ const EventButton = (obj) => { return null; } + // Displays info specific to a type of transactions let eventSpecificInfo; if (transactionName === "Reward") { if (transactionAmount - 69 < 1 && transactionAmount - 69 > 0) { diff --git a/src/eventViewer.js b/src/eventViewer.js index faf930d..73fd4fa 100644 --- a/src/eventViewer.js +++ b/src/eventViewer.js @@ -2,6 +2,8 @@ import React, { useState } from "react"; import EventButton from "./eventButton"; import ScrollContainer from 'react-indiana-drag-scroll'; +/// A scrollable and filterable list of EventButtons + const activationColour = "rgba(23, 60, 122, 0.3)"; const rewardColour = "rgba(20, 99, 29, 0.3)"; const updateColour = "rgba(122, 63, 23, 0.3)"; @@ -15,6 +17,7 @@ const EventViewer = (obj) => { const [updateActivated, setUpdateActivated] = useState(false); const [withdrawActivated, setWithdrawActivated] = useState(false); const [stakeActivated, setStakeActivated] = useState(false); + console.log("Rendering EventViewer"); let txCounter = 0; let currentTx = ""; diff --git a/src/grafana.js b/src/grafana.js index 2049898..0c2b8eb 100644 --- a/src/grafana.js +++ b/src/grafana.js @@ -6,6 +6,8 @@ import { import { useSelector } from 'react-redux' import Orchestrator from "./orchestratorViewer"; +// Displays orchestrator info and embedded grafana panels + const Grafana = (obj) => { const livepeer = useSelector((state) => state.livepeerstate); const [redirectToHome, setRedirectToHome] = useState(false); diff --git a/src/home.js b/src/home.js index d7229a7..ce85819 100644 --- a/src/home.js +++ b/src/home.js @@ -1,107 +1,84 @@ -import * as React from "react"; +import React, { useState } from 'react'; import './style.css'; import { Navigate } from "react-router-dom"; -import { connect } from "react-redux"; -import { - getVisitorStats -} from "./actions/user"; +import { useSelector } from 'react-redux' -const mapStateToProps = (state) => { - return { - session: state.session, - userstate: state.userstate, - errors: state.errors +// Index of all subpages on this website + +const Home = (obj) => { + const userstate = useSelector((state) => state.userstate); + const sessionstate = useSelector((state) => state.session); + const [redirectToGrafana, setRedirectToGrafana] = useState(false); + const [redirectToLPT, setRedirectToLPT] = useState(false); + + if (redirectToGrafana) { + return ; } -}; - -const mapDispatchToProps = dispatch => ({ - getVisitorStats: () => dispatch(getVisitorStats()) -}); - - -class Home extends React.Component { - state = { - redirectToGrafana: false, - redirectToLPT: false - }; - - constructor(props) { - super(props); + if (redirectToLPT) { + return ; } - render() { - if (this.state.redirectToGrafana) { - return ; - } - if (this.state.redirectToLPT) { - return ; - } + var totalVisitorCount = 0; + var activeVisitorCount = 0; + if (userstate.visitorStats) { + totalVisitorCount = userstate.visitorStats.totalVisitorCount; + activeVisitorCount = userstate.visitorStats.activeVisitorCount + } - var totalVisitorCount = 0; - var activeVisitorCount = 0; - if (this.props.userstate.visitorStats) { - totalVisitorCount = this.props.userstate.visitorStats.totalVisitorCount; - activeVisitorCount = this.props.userstate.visitorStats.activeVisitorCount - } - - return ( -
-
- -
-
-
-
-

Home

-
- -
- -
-
- -
+
-
-
-
-

- Connected as {this.props.session.ip || "?"} -

+
+
-
-

- {totalVisitorCount} unique visitors / {activeVisitorCount} of which have interacted with this website -

+
+
-
-
- nframe.nl -
-
- ) - } +
+
+

+ Connected as {sessionstate.ip || "?"} +

+
+
+

+ {totalVisitorCount} unique visitors / {activeVisitorCount} of which have interacted with this website +

+
+
+
+
+ nframe.nl +
+
+
+ ) } -export default connect( - mapStateToProps, - mapDispatchToProps -)(Home); +export default Home; diff --git a/src/livepeer.js b/src/livepeer.js index 380be4c..08017f8 100644 --- a/src/livepeer.js +++ b/src/livepeer.js @@ -1,43 +1,26 @@ import React, { useState, useEffect } from 'react' import './style.css'; -import { - Navigate, useSearchParams -} from "react-router-dom"; -import { useSelector, useDispatch, batch } from 'react-redux' -import { - getQuotes, getBlockchainData, getEvents, getCurrentOrchestratorInfo, getOrchestratorInfo -} from "./actions/livepeer"; +import { Navigate, useSearchParams } from "react-router-dom"; +import { useSelector, useDispatch } from 'react-redux' +import { getOrchestratorInfo } from "./actions/livepeer"; import EventViewer from "./eventViewer"; import Orchestrator from "./orchestratorViewer"; import Stat from "./statViewer"; -// Refresh every 30 seconds -const refreshInterval = 30000; +// Shows the EventViewer and other Livepeer related info const Livepeer = (obj) => { const [prefill, setPrefill] = useSearchParams(); const dispatch = useDispatch(); const livepeer = useSelector((state) => state.livepeerstate); const [redirectToHome, setRedirectToHome] = useState(false); - - const refreshAllZeData = () => { - batch(() => { - dispatch(getQuotes()) - dispatch(getEvents()) - dispatch(getBlockchainData()) - dispatch(getCurrentOrchestratorInfo()) - }); - } + console.log("Rendering Livepeer"); useEffect(() => { - if (prefill.get('orchAddr') != ""){ + if (prefill.get('orchAddr') != "") { dispatch(getOrchestratorInfo(prefill.get('orchAddr'))); } - if (refreshInterval) { - const interval = setInterval(refreshAllZeData, refreshInterval); - return () => clearInterval(interval); - } - }, [refreshInterval]); + }, [prefill]); if (redirectToHome) { return ; diff --git a/src/loadingScreen.js b/src/loadingScreen.js index 251f2bf..12116f2 100644 --- a/src/loadingScreen.js +++ b/src/loadingScreen.js @@ -1,5 +1,5 @@ -import * as React from "react"; -import { connect, batch } from "react-redux"; +import React, { useEffect, useState } from 'react' +import { useDispatch, batch } from 'react-redux' import { getVisitorStats } from "./actions/user"; @@ -8,41 +8,66 @@ import { } from "./actions/livepeer"; import { login } from "./actions/session"; -const mapStateToProps = (state) => { - return { - session: state.session, - userstate: state.userstate, - errors: state.errors - } -}; +// Shows a loading screen on first load and gets fresh data every refreshInterval milliseconds -const mapDispatchToProps = dispatch => ({ - getVisitorStats: () => dispatch(getVisitorStats()), - login: () => dispatch(login()), - getQuotes: () => dispatch(getQuotes()), - getEvents: () => dispatch(getEvents()), - getBlockchainData: () => dispatch(getBlockchainData()), - getCurrentOrchestratorInfo: () => dispatch(getCurrentOrchestratorInfo()) -}); +// Refresh every 30 seconds +const refreshInterval = 30000; +const Startup = (obj) => { + const [isLoaded, setIsLoaded] = useState(false); + const dispatch = useDispatch(); -class Startup extends React.Component { - componentDidMount() { + const refreshAllZeData = () => { + console.log("Refreshing data..."); batch(() => { - this.props.login(); - this.props.getVisitorStats(); - this.props.getQuotes(); - this.props.getBlockchainData(); - this.props.getEvents(); - this.props.getCurrentOrchestratorInfo(); + dispatch(getQuotes()); + dispatch(getEvents()); + dispatch(getBlockchainData()); + dispatch(getCurrentOrchestratorInfo()); }); } - render() { - return this.props.children; + + const refreshLogin = () => { + console.log("Logging in and getting visitor statistics..."); + batch(() => { + dispatch(login()); + dispatch(getVisitorStats()); + }); + setIsLoaded(true); + } + + useEffect(() => { + refreshLogin(); + refreshAllZeData(); + if (refreshInterval) { + const interval = setInterval(refreshAllZeData, refreshInterval); + return () => clearInterval(interval); + } + }, [refreshInterval]); + + if(isLoaded){ + console.log("Rendering Application"); + return obj.children; + }else{ + console.log("Rendering Loading Screen"); + return
+
+ +
+
+
+
+

Loading...

+
+
+
+
+
+ nframe.nl +
+
+
} } -export default connect( - mapStateToProps, - mapDispatchToProps -)(Startup); \ No newline at end of file +export default Startup; \ No newline at end of file diff --git a/src/reducers/root.js b/src/reducers/root.js index b110ec9..38461f9 100644 --- a/src/reducers/root.js +++ b/src/reducers/root.js @@ -3,8 +3,6 @@ import errors from "./errors/errors"; import session from "./session/session"; import userstate from "./userstate/userstate"; import livepeerstate from "./livepeer/livepeerstate"; -{/*Reducers define how the state of the application changes when actions are sent into the store. They take in the current state and the action that was performed. -This file combines all reducers in use so they are all accessible for redux*/} export default combineReducers({ session, errors, diff --git a/src/store/store.js b/src/store/store.js index da4e3b8..138c41a 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -2,7 +2,6 @@ import { createStore, applyMiddleware, compose } from "redux"; import thunk from "redux-thunk"; import reducer from "../reducers/root"; - function configureStore(preloadedState) { const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore(reducer, preloadedState, composeEnhancers( @@ -12,7 +11,6 @@ function configureStore(preloadedState) { return store; } - export default (preloadedState) => ( configureStore(preloadedState) ); \ No newline at end of file