Skip to content

Commit

Permalink
feat: use nova models on visualizer three (#1053)
Browse files Browse the repository at this point in the history
* feat: use nova models on visualizer three

* fix: remove unnecessary file and update client to nova

* fix: set long timestamp without time reference
  • Loading branch information
VmMad authored Feb 6, 2024
1 parent 111c587 commit 9b71714
Show file tree
Hide file tree
Showing 13 changed files with 226 additions and 176 deletions.
4 changes: 4 additions & 0 deletions api/src/initServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { NetworkService } from "./services/networkService";
import { NovaFeed } from "./services/nova/feed/novaFeed";
import { NodeInfoService as NodeInfoServiceNova } from "./services/nova/nodeInfoService";
import { NovaApiService } from "./services/nova/novaApiService";
import { NovaStatsService } from "./services/nova/stats/novaStatsService";
import { ChronicleService } from "./services/stardust/chronicleService";
import { StardustFeed } from "./services/stardust/feed/stardustFeed";
import { InfluxDBService } from "./services/stardust/influx/influxDbService";
Expand Down Expand Up @@ -223,6 +224,9 @@ function initNovaServices(networkConfig: INetwork): void {
ServiceFactory.register(`chronicle-${networkConfig.network}`, () => chronicleService);
}

const novaStatsService = new NovaStatsService(networkConfig);
ServiceFactory.register(`stats-${networkConfig.network}`, () => novaStatsService);

// eslint-disable-next-line no-void
void NovaClient.create(novaClientParams).then((novaClient) => {
ServiceFactory.register(`client-${networkConfig.network}`, () => novaClient);
Expand Down
56 changes: 56 additions & 0 deletions api/src/services/nova/stats/baseStatsService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { INetwork } from "../../../models/db/INetwork";
import { IStatistics } from "../../../models/services/IStatistics";
import { IStatsService } from "../../../models/services/IStatsService";

/**
* Class to handle stats service.
*/
export abstract class BaseStatsService implements IStatsService {
/**
* The network configuration.
*/
protected readonly _networkConfiguration: INetwork;

/**
* The statistics.
*/
protected _statistics: IStatistics[];

/**
* Create a new instance of BaseStatsService.
* @param networkConfiguration The network configuration.
*/
constructor(networkConfiguration: INetwork) {
this._networkConfiguration = networkConfiguration;
this._statistics = [
{
itemsPerSecond: 0,
confirmedItemsPerSecond: 0,
confirmationRate: 0,
},
];

setInterval(async () => this.updateStatistics(), 2000);
}

/**
* Get the current stats.
* @returns The statistics for the network.
*/
public getStats(): IStatistics {
return this._statistics.at(-1);
}

/**
* Get the stats history.
* @returns The historical statistics for the network.
*/
public getItemsPerSecondHistory(): number[] {
return this._statistics.map((s) => s.itemsPerSecond);
}

/**
* Gather more statistics.
*/
protected abstract updateStatistics(): Promise<void>;
}
37 changes: 37 additions & 0 deletions api/src/services/nova/stats/novaStatsService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// eslint-disable-next-line import/no-unresolved
import { Client } from "@iota/sdk-nova";
import { BaseStatsService } from "./baseStatsService";
import { ServiceFactory } from "../../../factories/serviceFactory";
import logger from "../../../logger";

/**
* Class to handle stats service.
*/
export class NovaStatsService extends BaseStatsService {
/**
* Gather general statistics.
*/
protected async updateStatistics(): Promise<void> {
try {
const client = ServiceFactory.get<Client>(`client-${this._networkConfiguration.network}`);
const response = await client.getInfo();

if (response) {
const metrics = response.nodeInfo.metrics;
this._statistics.push({
itemsPerSecond: Number(metrics.blocksPerSecond),
confirmedItemsPerSecond: Number(metrics.confirmedBlocksPerSecond),
confirmationRate: Number(metrics.confirmationRate),
});

logger.debug(`[NovaStatsService] Updating network statistics for ${this._networkConfiguration.network}`);

if (this._statistics.length > 30) {
this._statistics = this._statistics.slice(-30);
}
}
} catch (err) {
logger.debug(`[NovaStatsService] Update statistics failed: ${err}`);
}
}
}
29 changes: 29 additions & 0 deletions client/src/app/components/nova/block/BlockTangleState.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,35 @@
margin-top: 4px;
}

.block-tangle-reference {
display: flex;
white-space: pre-wrap;
@include font-size(12px);

color: $gray-5;
font-family: $inter;
font-weight: 500;
letter-spacing: 0.5px;

@include tablet-down {
margin-left: 8px;
flex-direction: column;
white-space: normal;
}

.block-tangle-reference__link {
color: var(--link-color);
cursor: pointer;
}

.time-reference {
&:hover {
cursor: pointer;
text-decoration: underline;
}
}
}

.block-tangle-state {
@include font-size(12px);

Expand Down
79 changes: 40 additions & 39 deletions client/src/app/components/nova/block/BlockTangleState.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import classNames from "classnames";
import React, { useEffect, useState } from "react";
import React from "react";
import Tooltip from "../../Tooltip";
import { BlockState, u64 } from "@iota/sdk-wasm-nova/web";
import { BlockFailureReason, BLOCK_FAILURE_REASON_STRINGS } from "@iota/sdk-wasm-nova/web/lib/types/models/block-failure-reason";
import moment from "moment";
import "./BlockTangleState.scss";
import { DateHelper } from "~/helpers/dateHelper";

export interface BlockTangleStateProps {
/**
Expand All @@ -24,45 +24,46 @@ export interface BlockTangleStateProps {
}

const BlockTangleState: React.FC<BlockTangleStateProps> = ({ status, issuingTime, failureReason }) => {
const [readableTimestamp, setReadableTimestamp] = useState<string | undefined>();

useEffect(() => {
const timestamp = DateHelper.format(DateHelper.milliseconds(Number(issuingTime) / 1000000));
setReadableTimestamp(timestamp);
}, [issuingTime]);
const blockIssueMoment = moment(Number(issuingTime) / 1000000);
const timeReference = blockIssueMoment.fromNow();
const longTimestamp = blockIssueMoment.format("LLLL");

return (
<div className="blocks-tangle-state">
{status && (
<React.Fragment>
<div
className={classNames(
"block-tangle-state",
{
"block-tangle-state__confirmed": status === "confirmed" || "finalized",
},
{
"block-tangle-state__conflicting": status === "rejected" && "failed",
},
{ "block-tangle-state__pending": status === "pending" },
)}
>
{failureReason ? (
<Tooltip tooltipContent={BLOCK_FAILURE_REASON_STRINGS[failureReason]}>
<span className="capitalize-text" style={{ color: "#ca493d" }}>
{status}
</span>
</Tooltip>
) : (
<span className="capitalize-text">{status}</span>
)}
</div>
<div className="block-tangle-reference">
<span> {readableTimestamp}</span>
</div>
</React.Fragment>
)}
</div>
<>
<div className="blocks-tangle-state">
{status && (
<React.Fragment>
<div
className={classNames(
"block-tangle-state",
{
"block-tangle-state__confirmed": status === "confirmed" || "finalized",
},
{
"block-tangle-state__conflicting": status === "rejected" && "failed",
},
{ "block-tangle-state__pending": status === "pending" },
)}
>
{failureReason ? (
<Tooltip tooltipContent={BLOCK_FAILURE_REASON_STRINGS[failureReason]}>
<span className="capitalize-text" style={{ color: "#ca493d" }}>
{status}
</span>
</Tooltip>
) : (
<span className="capitalize-text">{status}</span>
)}
</div>
<div className="block-tangle-reference">
<span title={longTimestamp} className="time-reference">
{timeReference}
</span>
</div>
</React.Fragment>
)}
</div>
</>
);
};

Expand Down
6 changes: 4 additions & 2 deletions client/src/app/types/visualizer.types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Viva from "vivagraphjs";
import { IFeedBlockData } from "../../models/api/stardust/feed/IFeedBlockData";
import { IFeedBlockData as IFeedBlockDataStardust } from "../../models/api/stardust/feed/IFeedBlockData";
import { IFeedBlockData as IFeedBlockDataNova } from "../../models/api/nova/feed/IFeedBlockData";
import { INodeData } from "../../models/graph/stardust/INodeData";

export type TSelectNode = (node?: Viva.Graph.INode<INodeData, unknown>) => void;

export type TSelectFeedItem = IFeedBlockData | null;
export type TSelectFeedItem = IFeedBlockDataStardust | null;
export type TSelectFeedItemNova = IFeedBlockDataNova | null;
8 changes: 6 additions & 2 deletions client/src/features/visualizer-threejs/VisualizerInstance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import { NovaFeedClient } from "../../services/nova/novaFeedClient";
import { Wrapper } from "./wrapper/Wrapper";
import { CanvasElement } from "./enums";
import { useGetThemeMode } from "~/helpers/hooks/useGetThemeMode";
import CameraControls from "./CameraControls";
import { TSelectFeedItemNova } from "~/app/types/visualizer.types";
import { BasicBlockBody, IBlockMetadata } from "@iota/sdk-wasm-nova/web";
import { IFeedBlockData } from "~/models/api/nova/feed/IFeedBlockData";
import CameraControls from "./CameraControls";
import "./Visualizer.scss";

const features = {
Expand Down Expand Up @@ -65,6 +66,9 @@ const VisualizerInstance: React.FC<RouteComponentProps<VisualizerRouteProps>> =
const addToColorQueue = useTangleStore((s) => s.addToColorQueue);
const blockMetadata = useTangleStore((s) => s.blockMetadata);
const indexToBlockId = useTangleStore((s) => s.indexToBlockId);
const clickedInstanceId = useTangleStore((s) => s.clickedInstanceId);

const selectedFeedItem: TSelectFeedItemNova = clickedInstanceId ? blockMetadata.get(clickedInstanceId) ?? null : null;

const emitterRef = useRef<THREE.Mesh>(null);
const feedServiceRef = useRef<NovaFeedClient | null>(null);
Expand Down Expand Up @@ -230,7 +234,7 @@ const VisualizerInstance: React.FC<RouteComponentProps<VisualizerRouteProps>> =
networkConfig={networkConfig}
onChangeFilter={() => {}}
selectNode={() => {}}
selectedFeedItem={null}
selectedFeedItem={selectedFeedItem}
setIsPlaying={setIsPlaying}
isEdgeRenderingEnabled={isEdgeRenderingEnabled}
setEdgeRenderingEnabled={(checked) => setEdgeRenderingEnabled(checked)}
Expand Down
2 changes: 1 addition & 1 deletion client/src/features/visualizer-threejs/store/tangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Color } from "three";
import { create } from "zustand";
import { devtools } from "zustand/middleware";
import { ZOOM_DEFAULT, ANIMATION_TIME_SECONDS } from "../constants";
import { IFeedBlockData } from "~models/api/stardust/feed/IFeedBlockData";
import { IFeedBlockData } from "~models/api/nova/feed/IFeedBlockData";

interface IPosition {
x: number;
Expand Down
5 changes: 1 addition & 4 deletions client/src/features/visualizer-threejs/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { IFeedBlockData } from "../../models/api/stardust/feed/IFeedBlockData";
import { IFeedBlockMetadata } from "../../models/api/stardust/feed/IFeedBlockMetadata";
import { IFeedBlockData } from "../../models/api/nova/feed/IFeedBlockData";

export type TFeedBlockAdd = (newBlock: IFeedBlockData) => void;

export type TFeedBlockMetadataUpdate = (metadataUpdate: { [id: string]: IFeedBlockMetadata }) => void;

export type TangleMeshType = THREE.Mesh<THREE.PlaneGeometry, THREE.MeshBasicMaterial, THREE.Object3DEventMap>;
Loading

0 comments on commit 9b71714

Please sign in to comment.