mirror of
https://github.com/stronk-dev/LivepeerEvents.git
synced 2026-04-20 12:25:10 +02:00
Background loading enabled, moved out of specific components
This commit is contained in:
parent
a98bd49e37
commit
3b4990865c
@ -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);
|
||||
|
||||
@ -10,7 +10,6 @@ import {
|
||||
Route
|
||||
} from "react-router-dom";
|
||||
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Startup>
|
||||
@ -30,4 +29,4 @@ export default function App() {
|
||||
</Router>
|
||||
</Startup>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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 = "";
|
||||
|
||||
@ -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);
|
||||
|
||||
157
src/home.js
157
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 <Navigate push to="/orchestrator" />;
|
||||
}
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
getVisitorStats: () => dispatch(getVisitorStats())
|
||||
});
|
||||
|
||||
|
||||
class Home extends React.Component {
|
||||
state = {
|
||||
redirectToGrafana: false,
|
||||
redirectToLPT: false
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (redirectToLPT) {
|
||||
return <Navigate push to="/livepeer" />;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.redirectToGrafana) {
|
||||
return <Navigate push to="/orchestrator" />;
|
||||
}
|
||||
if (this.state.redirectToLPT) {
|
||||
return <Navigate push to="/livepeer" />;
|
||||
}
|
||||
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 (
|
||||
<div className="stroke" style={{ padding: 0 }}>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<img alt="" src="livepeer.png" width="100em" height="100em" style={{ zIndex: 10 }} />
|
||||
</div>
|
||||
<div className="flexContainer">
|
||||
<div className="stroke roundedOpaque">
|
||||
<div className="row">
|
||||
<h3>Home</h3>
|
||||
</div>
|
||||
<div className="row">
|
||||
<a href="https://github.com/stronk-dev/LivepeerEvents">
|
||||
<button className="waveButton">
|
||||
<p>🧱 Source Code 🏠</p>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<div className="row">
|
||||
<button className="waveButton" onClick={() => {
|
||||
this.setState({ redirectToGrafana: true });
|
||||
}}>
|
||||
<p>🚀 Orchestrator 🌑</p>
|
||||
return (
|
||||
<div className="stroke" style={{ padding: 0 }}>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<img alt="" src="livepeer.png" width="100em" height="100em" style={{ zIndex: 10 }} />
|
||||
</div>
|
||||
<div className="flexContainer">
|
||||
<div className="stroke roundedOpaque">
|
||||
<div className="row">
|
||||
<h3>Home</h3>
|
||||
</div>
|
||||
<div className="row">
|
||||
<a href="https://github.com/stronk-dev/LivepeerEvents">
|
||||
<button className="waveButton">
|
||||
<p>🧱 Source Code 🏠</p>
|
||||
</button>
|
||||
</div>
|
||||
<div className="row">
|
||||
<button className="waveButton" onClick={() => {
|
||||
this.setState({ redirectToLPT: true });
|
||||
}}>
|
||||
<p>🔎 Blockchain 🕵️</p>
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="alwaysOnBottom showNeverOnMobile" style={{ margin: 0, padding: 0 }}>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<h4 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
Connected as {this.props.session.ip || "?"}
|
||||
</h4>
|
||||
<div className="row">
|
||||
<button className="waveButton" onClick={() => {
|
||||
setRedirectToGrafana(true);
|
||||
}}>
|
||||
<p>🚀 Orchestrator 🌑</p>
|
||||
</button>
|
||||
</div>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<h3 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
{totalVisitorCount} unique visitors / {activeVisitorCount} of which have interacted with this website
|
||||
</h3>
|
||||
<div className="row">
|
||||
<button className="waveButton" onClick={() => {
|
||||
setRedirectToLPT(true);
|
||||
}}>
|
||||
<p>🔎 Blockchain 🕵️</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="alwaysOnBottomRight" style={{ margin: 0, padding: 0 }}>
|
||||
<h6 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
nframe.nl
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className="alwaysOnBottom showNeverOnMobile" style={{ margin: 0, padding: 0 }}>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<h4 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
Connected as {sessionstate.ip || "?"}
|
||||
</h4>
|
||||
</div>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<h3 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
{totalVisitorCount} unique visitors / {activeVisitorCount} of which have interacted with this website
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="alwaysOnBottomRight" style={{ margin: 0, padding: 0 }}>
|
||||
<h6 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
nframe.nl
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Home);
|
||||
export default Home;
|
||||
|
||||
@ -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 <Navigate push to="/" />;
|
||||
|
||||
@ -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 <div className="stroke" style={{ padding: 0 }}>
|
||||
<div className="row" style={{ margin: 0, padding: 0 }}>
|
||||
<img alt="" src="livepeer.png" width="100em" height="100em" style={{ zIndex: 10 }} />
|
||||
</div>
|
||||
<div className="flexContainer">
|
||||
<div className="stroke roundedOpaque">
|
||||
<div className="row">
|
||||
<h3>Loading...</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="alwaysOnBottomRight" style={{ margin: 0, padding: 0 }}>
|
||||
<h6 className="lightText" style={{ margin: 0, padding: 0 }}>
|
||||
nframe.nl
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Startup);
|
||||
export default Startup;
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
);
|
||||
Loading…
x
Reference in New Issue
Block a user