瀏覽代碼

QN info, useMemo

Joystream Stats 2 年之前
父節點
當前提交
7f593531c3

+ 35 - 32
src/components/Distribution/Bucket.tsx

@@ -1,4 +1,4 @@
-import { useState, useEffect } from "react";
+import { useState, useEffect, useMemo } from "react";
 import { Badge } from "react-bootstrap";
 import Metadata from "./Metadata";
 import Bags from "./Bags";
@@ -7,47 +7,49 @@ import { testQN } from "./util";
 import { Operator, Bucket } from "./types";
 
 const BucketRow = (props: { isDP: boolean; bucket: Bucket }) => {
-  const [show, setShow] = useState(false);
-  const [hasQN, setQN] = useState(false);
-  const [qnTitle, setTitle] = useState(``);
   const { isDP, bucket } = props;
   const { id, distributing, acceptingNewBags, bags, operatorMetadata } = bucket;
-  const operator = isDP ? bucket.operators[0] : { metadata: operatorMetadata };
-
-  useEffect(() => testQN(operator, setQN, setTitle));
+  const op = useMemo(
+    () => (isDP ? bucket.operators[0] : { metadata: operatorMetadata }),
+    [isDP]
+  );
+  const [show, setShow] = useState(false);
+  const [hasQN, setQN] = useState();
+  const [qnInfo, setInfo] = useState(``);
+  const [qnUrl, setUrl] = useState();
+  const [families, setFams] = useState([]);
+  useEffect(
+    () => qnUrl || testQN(op, setQN, setInfo, setUrl, setFams),
+    [op, !qnUrl]
+  );
+  let qnTitle = `Not set.`;
+  if (qnInfo.length) {
+    const no = families.length ? "" : "no ";
+    qnTitle = `${no}functional QueryNode: ${families.length} Bucket Families received.\n${qnInfo}`;
+  } else if (qnUrl?.length) qnTitle = `Checking..`;
 
+  const dTitle = (distributing ? "" : "not ") + "distributing";
+  const aTitle = (acceptingNewBags ? "" : "not ") + "accepting new bags";
   return (
     <>
-      <div key={id} className="d-flex flex-row" onClick={() => setShow(!show)}>
-        <StatusBadge
-          status={hasQN}
-          label={"Q"}
-          title={(hasQN ? "" : "no ") + "functional query node: " + qnTitle}
-        />
+      <div key={id} className="d-flex flex-row">
+        <a href={qnUrl}>
+          <StatusBadge status={hasQN} label={"Q"} title={qnTitle} />
+        </a>
 
         <div className="col-1 text-right d-flex justify-content-between">
           <h3>{id}</h3>
           {isDP && (
-            <StatusBadge
-              status={distributing}
-              label={"D"}
-              title={(distributing ? "" : "not ") + "distributing"}
-            />
+            <StatusBadge status={distributing} label={"D"} title={dTitle} />
           )}
         </div>
-        <StatusBadge
-          status={acceptingNewBags}
-          label={"A"}
-          title={(acceptingNewBags ? "" : "not ") + "accepting new bags"}
-        />
-        <div className="col-1">{bags.length} bags</div>
-        <OperatorFields operator={operator} />
+        <StatusBadge status={acceptingNewBags} label={"A"} title={aTitle} />
+        <div className="col-1" onClick={() => setShow(!show)}>
+          {bags.length} bags
+        </div>
+        <OperatorFields operator={op} />
       </div>
-      {show ? (
-        <Bags show={show} bucketId={id} bags={bags} operator={operator} />
-      ) : (
-        ``
-      )}
+      {show ? <Bags show={show} bucketId={id} bags={bags} operator={op} /> : ``}
     </>
   );
 };
@@ -55,8 +57,9 @@ const BucketRow = (props: { isDP: boolean; bucket: Bucket }) => {
 export default BucketRow;
 
 const OperatorFields = (props: { operator: Operator }) => {
-  if (!props.operator) return <div className="col-7">No operator info.</div>;
-  const { workerId, member, metadata } = props.operator;
+  const { operator } = props;
+  if (!operator) return <div className="col-7">No operator assigned.</div>;
+  const { workerId, member, metadata } = operator;
   return (
     <>
       <div

+ 1 - 1
src/components/Distribution/Status.tsx

@@ -8,7 +8,7 @@ const Status = (props: { endpoint: string }) => {
   const { endpoint } = props;
   const [status, setStatus] = useState({});
   const updateStatus = (url: string) => {
-    console.debug(`udating status`, url);
+    console.debug(`testing provider`, url);
     axios
       .get(url)
       .then(({ data }) => setStatus(data))

+ 6 - 0
src/components/Distribution/types.ts

@@ -6,6 +6,12 @@ export interface Operator {
   };
 }
 
+export interface Family {
+  id: string;
+  buckets: { id: string; bags: { id: string } }[];
+  metadata: { description: string; region: string };
+}
+
 export interface Bucket {
   id: string;
   createdAt: string;

+ 29 - 18
src/components/Distribution/util.ts

@@ -2,6 +2,7 @@ import axios from "axios";
 import { queryNode } from "../../config";
 import { Operator, Bucket } from "./types";
 import { qnBuckets, qnBucketObjects } from "./queries";
+import { Family } from "./types";
 
 export const gb = (bytes: number) => (bytes / 1024 ** 3).toFixed() + `gb`;
 
@@ -9,9 +10,9 @@ const fail = (msg: string) => {
   console.log(`postQN: ${msg}`);
   return [];
 };
-export const postQN = (query) =>
+export const postQN = (query: string, url: string = queryNode) =>
   axios
-    .post(queryNode, { query })
+    .post(url, { query })
     .then(({ data }) => {
       if (data.error) return fail(data.error);
       console.debug(`postQN`, query, data.data);
@@ -39,23 +40,33 @@ export const testBag = async (
 };
 
 export const testQN = (
-  operator: Operator,
+  op: Operator,
   setStatus: (b: boolean) => void,
-  setTitle: (s: string) => void
-) => {
-  const query = `query { distributionBucketFamilies { id metadata{description region} buckets { id bags { id } }} }`;
-  const qnUrl = operator?.metadata?.nodeEndpoint?.replace(
-    /[^\/]+\/?$/,
-    `graphql`
-  );
-  return axios
-    .post(qnUrl, { query })
-    .then(({ data }) => {
-      setStatus(true);
-      console.log(data);
-      if (data) setTitle(JSON.stringify(data));
-    }) // TODO extra test to verify data
-    .catch((e) => setTitle(e.message + JSON.stringify(e)));
+  setInfo: (s: string) => void,
+  setUrl: (s: string) => void,
+  setFamilies: (f: Family[]) => void
+): Promise<void> => {
+  const query = `query { distributionBucketFamilies {id,metadata{description,region} buckets{id}}}`;
+  const qnUrl = op?.metadata?.nodeEndpoint?.replace(/[^/]+\/?$/, `graphql`);
+  setUrl(qnUrl || ``);
+  if (!qnUrl) return;
+  setTimeout(() => {
+    console.debug(`testing QN`, qnUrl);
+    try {
+      axios.post(qnUrl, { query }).then(({ data }) => {
+        if (!data.data || data.errors)
+          return setInfo(JSON.stringify(data.errors));
+        setStatus(true);
+        setInfo(JSON.stringify(data.data));
+        if (data.data.distributionBucketFamilies?.length)
+          setFamilies(data.data.distributionBucketFamilies);
+      }); // TODO extra test to verify data
+      //.catch((e) => setInfo(e.message + JSON.stringify(e)));
+    } catch (e) {
+      setInfo(e.message + JSON.stringify(e));
+      console.debug(qnUrl, e.message);
+    }
+  }, 1000);
 };
 
 export const getBucketObjects = async (bucketId: number) =>