Skip to content
Snippets Groups Projects
Commit 1ed1bbac authored by capossele's avatar capossele
Browse files

:construction: dRNG dashboard tab WIP

parent cac95695
No related branches found
No related tags found
No related merge requests found
package spa
import (
"time"
"github.com/iotaledger/hive.go/daemon"
"github.com/iotaledger/hive.go/events"
"github.com/iotaledger/hive.go/workerpool"
"github.com/iotaledger/goshimmer/packages/binary/messagelayer/message"
"github.com/iotaledger/goshimmer/packages/binary/messagelayer/tangle"
"github.com/iotaledger/goshimmer/packages/shutdown"
"github.com/iotaledger/goshimmer/plugins/messagelayer"
)
var drngLiveFeedWorkerCount = 1
var drngLiveFeedWorkerQueueSize = 50
var drngLiveFeedWorkerPool *workerpool.WorkerPool
func configureDrngLiveFeed() {
liveFeedWorkerPool = workerpool.New(func(task workerpool.Task) {
task.Param(0).(*message.CachedMessage).Consume(func(message *message.Message) {
sendToAllWSClient(&msg{MsgTypeTx, &tx{message.Id().String(), 0}})
})
task.Return(nil)
}, workerpool.WorkerCount(drngLiveFeedWorkerCount), workerpool.QueueSize(drngLiveFeedWorkerQueueSize))
}
func runDrngLiveFeed() {
newMsgRateLimiter := time.NewTicker(time.Second / 10)
notifyNewMsg := events.NewClosure(func(message *message.CachedMessage, metadata *tangle.CachedMessageMetadata) {
metadata.Release()
select {
case <-newMsgRateLimiter.C:
drngLiveFeedWorkerPool.TrySubmit(message)
default:
message.Release()
}
})
daemon.BackgroundWorker("SPA[DrngUpdater]", func(shutdownSignal <-chan struct{}) {
messagelayer.Tangle.Events.TransactionAttached.Attach(notifyNewMsg)
drngLiveFeedWorkerPool.Start()
<-shutdownSignal
log.Info("Stopping SPA[DrngUpdater] ...")
messagelayer.Tangle.Events.TransactionAttached.Detach(notifyNewMsg)
newMsgRateLimiter.Stop()
drngLiveFeedWorkerPool.Stop()
log.Info("Stopping SPA[DrngUpdater] ... done")
}, shutdown.ShutdownPrioritySPA)
}
This diff is collapsed.
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.2.2", "@babel/core": "^7.2.2",
"@jimp/custom": "^0.10.1",
"@jimp/plugin-blur": "^0.10.1",
"@jimp/plugin-color": "^0.10.1",
"@jimp/plugin-resize": "^0.10.1",
"@types/classnames": "^2.2.7", "@types/classnames": "^2.2.7",
"@types/react": "^16.7.20", "@types/react": "^16.7.20",
"@types/react-dom": "^16.0.11", "@types/react-dom": "^16.0.11",
...@@ -23,8 +27,10 @@ ...@@ -23,8 +27,10 @@
"file-loader": "^3.0.1", "file-loader": "^3.0.1",
"html-loader": "^1.0.0-alpha.0", "html-loader": "^1.0.0-alpha.0",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"jquery": "^3.4.1",
"mini-css-extract-plugin": "^0.5.0", "mini-css-extract-plugin": "^0.5.0",
"mobx-react-devtools": "^6.0.3", "mobx-react-devtools": "^6.0.3",
"popper.js": "^1.16.1",
"postcss": "^7.0.13", "postcss": "^7.0.13",
"postcss-browser-reporter": "^0.5.0", "postcss-browser-reporter": "^0.5.0",
"postcss-import": "^12.0.1", "postcss-import": "^12.0.1",
...@@ -58,9 +64,11 @@ ...@@ -58,9 +64,11 @@
"classnames": "^2.2.6", "classnames": "^2.2.6",
"dateformat": "^3.0.3", "dateformat": "^3.0.3",
"favicons-webpack-plugin": "^2.1.0", "favicons-webpack-plugin": "^2.1.0",
"history": "^4.10.1",
"mobx": "^5.15.0", "mobx": "^5.15.0",
"mobx-react": "^5.4.3", "mobx-react": "^5.4.3",
"mobx-react-router": "^4.0.5", "mobx-react-router": "^4.0.5",
"moment": "^2.24.0",
"prettysize": "^2.0.0", "prettysize": "^2.0.0",
"react": "^16.7.0", "react": "^16.7.0",
"react-apexcharts": "^1.3.3", "react-apexcharts": "^1.3.3",
......
import * as React from 'react';
import Container from "react-bootstrap/Container";
import NodeStore from "app/stores/NodeStore";
import {inject, observer} from "mobx-react";
import {DrngLiveFeed} from "app/components/DrngLiveFeed";
interface Props {
nodeStore?: NodeStore;
}
@inject("nodeStore")
@observer
export class Drng extends React.Component<Props, any> {
render() {
return (
<Container>
<h3>dRNG Explorer</h3>
<DrngLiveFeed/>
</Container>
);
}
}
import * as React from 'react';
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import NodeStore from "app/stores/NodeStore";
import {inject, observer} from "mobx-react";
import Card from "react-bootstrap/Card";
import DrngStore from "app/stores/DrngStore";
import Table from "react-bootstrap/Table";
interface Props {
nodeStore?: NodeStore;
drngStore?: DrngStore;
}
@inject("nodeStore")
@inject("drngStore")
@observer
export class DrngLiveFeed extends React.Component<Props, any> {
render() {
let {msgsLiveFeed} = this.props.drngStore;
return (
<Row className={"mb-3"}>
<Col>
<Card>
<Card.Body>
<Card.Title>Live Feed</Card.Title>
<Row className={"mb-3"}>
<Col xs={12}>
<h6>Messages</h6>
<Table>
<thead>
<tr>
<td>ID</td>
<td>Random value</td>
</tr>
</thead>
<tbody>
{msgsLiveFeed}
</tbody>
</Table>
</Col>
</Row>
</Card.Body>
</Card>
</Col>
</Row>
);
}
}
...@@ -6,6 +6,7 @@ import Nav from "react-bootstrap/Nav"; ...@@ -6,6 +6,7 @@ import Nav from "react-bootstrap/Nav";
import {Dashboard} from "app/components/Dashboard"; import {Dashboard} from "app/components/Dashboard";
import Badge from "react-bootstrap/Badge"; import Badge from "react-bootstrap/Badge";
import {RouterStore} from 'mobx-react-router'; import {RouterStore} from 'mobx-react-router';
import {Drng} from "app/components/Drng";
import {Explorer} from "app/components/Explorer"; import {Explorer} from "app/components/Explorer";
import {NavExplorerSearchbar} from "app/components/NavExplorerSearchbar"; import {NavExplorerSearchbar} from "app/components/NavExplorerSearchbar";
import {Redirect, Route, Switch} from 'react-router-dom'; import {Redirect, Route, Switch} from 'react-router-dom';
...@@ -53,6 +54,11 @@ export class Root extends React.Component<Props, any> { ...@@ -53,6 +54,11 @@ export class Root extends React.Component<Props, any> {
Tangle Explorer Tangle Explorer
</Nav.Link> </Nav.Link>
</LinkContainer> </LinkContainer>
<LinkContainer to="/drng">
<Nav.Link>
dRNG Explorer
</Nav.Link>
</LinkContainer>
</Nav> </Nav>
<Navbar.Collapse className="justify-content-end"> <Navbar.Collapse className="justify-content-end">
<NavExplorerSearchbar/> <NavExplorerSearchbar/>
...@@ -70,6 +76,7 @@ export class Root extends React.Component<Props, any> { ...@@ -70,6 +76,7 @@ export class Root extends React.Component<Props, any> {
<Route exact path="/explorer/addr/:hash" component={ExplorerAddressQueryResult}/> <Route exact path="/explorer/addr/:hash" component={ExplorerAddressQueryResult}/>
<Route exact path="/explorer/404/:search" component={Explorer404}/> <Route exact path="/explorer/404/:search" component={Explorer404}/>
<Route exact path="/explorer" component={Explorer}/> <Route exact path="/explorer" component={Explorer}/>
<Route exact path="/drng" component={Drng}/>
<Redirect to="/dashboard"/> <Redirect to="/dashboard"/>
</Switch> </Switch>
{this.props.children} {this.props.children}
......
...@@ -3,6 +3,7 @@ export enum WSMsgType { ...@@ -3,6 +3,7 @@ export enum WSMsgType {
TPSMetrics, TPSMetrics,
Tx, Tx,
NeighborStats, NeighborStats,
Drng,
} }
export interface WSMessage { export interface WSMessage {
......
import {action, computed, observable} from 'mobx';
import {registerHandler, WSMsgType} from "app/misc/WS";
import * as React from "react";
import {Link} from 'react-router-dom';
import {RouterStore} from "mobx-react-router";
export class DrngMessage {
instanceId: number;
round: number;
value: number;
timestamp: number;
}
class Msg {
hash: string;
randomValue: number;
}
const liveFeedSize = 10;
export class DrngStore {
// live feed
@observable latest_msgs: Array<Msg> = [];
// queries
@observable msg: DrngMessage = null;
// loading
@observable query_loading: boolean = false;
@observable query_err: any = null;
routerStore: RouterStore;
constructor(routerStore: RouterStore) {
this.routerStore = routerStore;
registerHandler(WSMsgType.Drng, this.addLiveFeed);
}
@action
addLiveFeed = (msg: Msg) => {
// prevent duplicates (should be fast with only size 10)
if (this.latest_msgs.findIndex((t) => t.hash == msg.hash) === -1) {
if (this.latest_msgs.length >= liveFeedSize) {
this.latest_msgs.shift();
}
this.latest_msgs.push(msg);
}
};
@computed
get msgsLiveFeed() {
let feed = [];
for (let i = this.latest_msgs.length - 1; i >= 0; i--) {
let msg = this.latest_msgs[i];
feed.push(
<tr key={msg.hash}>
<td>
<Link to={`/drng/msg/${msg.hash}`}>
{msg.hash.substr(0, 35)}
</Link>
</td>
<td>
{msg.randomValue}
</td>
</tr>
);
}
return feed;
}
}
export default DrngStore;
\ No newline at end of file
...@@ -8,15 +8,18 @@ import {RouterStore, syncHistoryWithStore} from 'mobx-react-router'; ...@@ -8,15 +8,18 @@ import {RouterStore, syncHistoryWithStore} from 'mobx-react-router';
import {Router} from 'react-router-dom'; import {Router} from 'react-router-dom';
import NodeStore from "app/stores/NodeStore"; import NodeStore from "app/stores/NodeStore";
import ExplorerStore from "app/stores/ExplorerStore"; import ExplorerStore from "app/stores/ExplorerStore";
import DrngStore from "app/stores/DrngStore";
// prepare MobX stores // prepare MobX stores
const routerStore = new RouterStore(); const routerStore = new RouterStore();
const nodeStore = new NodeStore(); const nodeStore = new NodeStore();
const explorerStore = new ExplorerStore(routerStore); const explorerStore = new ExplorerStore(routerStore);
const drngStore = new DrngStore(routerStore);
const stores = { const stores = {
"routerStore": routerStore, "routerStore": routerStore,
"nodeStore": nodeStore, "nodeStore": nodeStore,
"explorerStore": explorerStore, "explorerStore": explorerStore,
"drngStore": drngStore,
}; };
const browserHistory = createBrowserHistory(); const browserHistory = createBrowserHistory();
......
...@@ -126,6 +126,7 @@ const ( ...@@ -126,6 +126,7 @@ const (
MsgTypeTPSMetric MsgTypeTPSMetric
MsgTypeTx MsgTypeTx
MsgTypeNeighborMetric MsgTypeNeighborMetric
MsgTypeDrng
) )
type msg struct { type msg struct {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment