Browse Source

Storage Liaisons

Joystream Stats 2 years ago
parent
commit
d0d08db0e5

+ 2 - 1
src/App.tsx

@@ -12,6 +12,7 @@ import {
   getCouncilSize,
   getVotes,
 } from "./lib/election";
+import { getAssets, getStorageProviders } from "./lib/storage";
 import {
   getStashes,
   getNominators,
@@ -60,7 +61,7 @@ class App extends React.Component<IProps, IState> {
     status.election = await updateElection(api);
     if (status.election?.stage) this.getElectionStatus(api);
     councils.forEach((c) => {
-      if (c.round > status.council) status.council = c;
+      if (c?.round > status.council) status.council = c;
     });
 
     let hash: string = await api.rpc.chain.getBlockHash(1);

+ 74 - 0
src/components/Storage/Liaisons.tsx

@@ -0,0 +1,74 @@
+interface Asset {}
+
+const getVideosPerProvider = (assets: Asset[]) => {
+  const providers = {};
+  assets.forEach((a) => {
+    if (!a.mediaDataObject?.liaison) return;
+    const liaison = a.mediaDataObject.liaison;
+    const worker = liaison.workerId;
+
+    if (!providers[worker])
+      providers[worker] = { first: a.createdAt, ...liaison, videos: [] };
+
+    providers[worker].videos.push(a);
+
+    if (providers[worker].first > a.createdAt)
+      providers[worker].first = a.createdAt;
+  });
+
+  const lastProviderAdded = Object.values(providers).reduce(
+    (max, provider) => (max > provider.first ? max : provider.first),
+    Object.values(providers)[0].first
+  );
+
+  return Object.values(providers)
+    .map((p) => {
+      const recent = p.videos.filter(
+        (v) => v.createdAt > lastProviderAdded
+      ).length;
+      return { ...p, recent };
+    })
+    .sort((a, b) => b.recent - a.recent);
+};
+
+const Liasons = (props: { assets: Asset[] }) => {
+  const { assets } = props;
+  if (!assets.length) return <div />;
+  return (
+    <div className="m-0">
+      <h3 className="text-center">Liaisons per Worker</h3>
+      <div className="d-flex flex-column m-0">
+        <div className="d-flex flex-row">
+          <div className="col-1 text-right">Worker</div>
+          <div className="col-6 text-left">Metadata</div>
+          <div className="col-1 text-right">Videos</div>
+          <div className="col-2">First Liaison</div>
+          <div className="col-1" title="Since Last Provider Added">
+            Recent
+          </div>
+          <div className="col-1 d-none d-md-block text-right">Pending</div>
+        </div>
+        {getVideosPerProvider(assets).map(
+          ({ recent, first, workerId, metadata, videos }) => (
+            <div key={workerId} className="d-flex flex-row m-0">
+              <div className="col-1 text-right">{workerId}</div>
+              <div className="col-6 text-left">{metadata}</div>
+              <div className="col-1 text-right">{videos.length}</div>
+              <div className="col-2">{first.split("T")[0]}</div>
+              <div className="col-1">{recent}</div>
+              <div className="col-1 d-none d-md-block text-right ">
+                {
+                  videos.filter(
+                    (v) => v.mediaDataObject.liaisonJudgement !== "ACCEPTED"
+                  ).length
+                }
+              </div>
+            </div>
+          )
+        )}
+      </div>
+    </div>
+  );
+};
+
+export default Liasons;

+ 2 - 1
src/components/Storage/Test.tsx

@@ -28,7 +28,8 @@ const Test = (props: {
   if (!providers.length) return <Loading target="providers" />;
   if (!assets.length) return <Loading target="assets" />;
   return (
-    <div className="m-2 p-2 bg-secondary">
+    <div className="mt-3 m-2 p-2 bg-secondary">
+    <h3 className="text-center">Live Speed Test</h3>
       <div className="form-group">
         <input
           className="form-control"

+ 12 - 19
src/components/Storage/index.tsx

@@ -1,6 +1,7 @@
 import React from "react";
 import { Button } from "react-bootstrap";
 import Ranking from "./Ranking";
+import Liaisons from "./Liaisons";
 
 import moment from "moment";
 import Test from "./Test";
@@ -36,7 +37,6 @@ class Storage extends React.Component<IProps, IState> {
 
   componentDidMount() {
     this.fetchSpeeds();
-    //setInterval(this.forceUpdate, 5000);
   }
 
   async fetchSpeeds() {
@@ -62,9 +62,9 @@ class Storage extends React.Component<IProps, IState> {
       return this.setState({ loading, startedAt: moment(), selectedAssets });
     }
 
-    for (let i = 0; i < number; i++) {
+    for (let i = 0; i < number; ++i) {
       const id = Math.round(Math.random() * assets.length);
-      const asset = assets.slice(id, id + 1)[0];
+      const asset = assets[id]?.mediaDataObject.joystreamContentId;
 
       if (selectedAssets.find((a) => a === asset)) i--;
       else selectedAssets.push(asset);
@@ -75,7 +75,7 @@ class Storage extends React.Component<IProps, IState> {
   }
 
   setAssetStatus(id: string, provider: string, status: string) {
-    console.debug(id, provider, status);
+    console.info(`${provider}asset/v0/${id}`, status);
     const tag = `${provider}-${id}`;
     const { loading } = this.state;
 
@@ -115,14 +115,8 @@ class Storage extends React.Component<IProps, IState> {
   }
 
   render() {
-    const {
-      speeds,
-      selectedAssets,
-      hash,
-      number,
-      loading,
-      showTest,
-    } = this.state;
+    const { speeds, selectedAssets, hash, number, loading, showTest } =
+      this.state;
     const { providers, assets, tokenomics } = this.props;
 
     return (
@@ -136,12 +130,11 @@ class Storage extends React.Component<IProps, IState> {
         ) : (
           <div />
         )}
+        <a className="text-dark" href="/static/helios">
+          HELIOS reports
+        </a>
 
-        <ul>
-          <li>
-            <a href="/static/helios">HELIOS reports</a>
-          </li>
-        </ul>
+        <Liaisons assets={assets} />
 
         {showTest ? (
           <Test
@@ -164,8 +157,8 @@ class Storage extends React.Component<IProps, IState> {
           </Button>
         )}
 
-        <h3>Ranking</h3>
-        <div className="d-flex flex-wrap ">
+        <h3 className="mt-3 text-center">Ranking</h3>
+        <div className="d-flex flex-wrap">
           {Object.keys(speeds).map((location) => (
             <Ranking
               key={location}

+ 29 - 17
src/lib/storage.ts

@@ -1,31 +1,43 @@
 import axios from "axios";
+import { hydraLocation } from "../config";
 
 export const getAssets = async () => {
-  const url = "https://hydra.joystream.org/graphql";
-  const request = {
-    query: "query {\n dataObjects(where: {}) { joystreamContentId }\n}",
+  const query = {
+    query: `\nquery {
+  videos (limit:1000000, orderBy:createdAt_DESC){
+    id
+    title
+    updatedAt
+    createdAt
+    createdInBlock
+    mediaDataObject {
+      joystreamContentId
+      liaisonJudgement
+      ipfsContentId
+      liaison {
+        workerId
+        metadata
+        isActive
+      }
+    }
+  }
+}\n`,
   };
-  console.debug(`Fetching data IDs from ${url}`);
-  const { data } = await axios.post(url, request);
-  let assets = [];
-  data.data.dataObjects.forEach((p) => assets.push(p.joystreamContentId));
-  return data;
+  console.debug(`Fetching data IDs from ${hydraLocation}`);
+  return axios.post(hydraLocation, query).then(({ data }) => data.data.videos);
 };
 
 export const getStorageProviders = async () => {
-  const url = "https://hydra.joystream.org/graphql";
   const request = {
     query:
       'query {\n  workers(where: {metadata_contains: "http", isActive_eq: true, type_eq: STORAGE}){\n    metadata\n  }\n}',
   };
-  console.debug(`Fetching storage providers from ${url}`);
-  const { data } = await axios.post(url, request);
-  const providers = data.data.workers.map((p) => {
-    return {
-      url: p.metadata,
-    };
-  });
-  return providers;
+  console.debug(`Fetching storage providers from ${hydraLocation}`);
+  return axios.post(hydraLocation, request).then(({ data }) =>
+    data.data.workers.map((p) => {
+      return { url: p.metadata };
+    })
+  );
 };
 
 export const getStorageProvidersFromApi = async (api: Api) => {