mirror of
https://github.com/logos-storage/logos-storage-marketplace-ui.git
synced 2026-01-05 23:13:08 +00:00
Use the debug info port to check the port forwarding
This commit is contained in:
parent
a102f3835a
commit
21fe557157
@ -1,32 +1,10 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
|
||||||
import { CodexSdk } from "../../sdk/codex";
|
|
||||||
import { Promises } from "../../utils/promises";
|
|
||||||
import { Spinner } from "@codex-storage/marketplace-ui-components";
|
import { Spinner } from "@codex-storage/marketplace-ui-components";
|
||||||
|
import { useDebug } from "../../hooks/useDebug";
|
||||||
|
|
||||||
|
const throwOnError = true;
|
||||||
|
|
||||||
export function Debug() {
|
export function Debug() {
|
||||||
const { data, isPending } = useQuery({
|
const { data, isPending } = useDebug(throwOnError);
|
||||||
queryFn: () =>
|
|
||||||
CodexSdk.debug()
|
|
||||||
.info()
|
|
||||||
.then((s) => Promises.rejectOnError(s)),
|
|
||||||
|
|
||||||
queryKey: ["debug"],
|
|
||||||
|
|
||||||
// No need to retry because if the connection to the node
|
|
||||||
// is back again, all the queries will be invalidated.
|
|
||||||
retry: false,
|
|
||||||
|
|
||||||
// The client node should be local, so display the cache value while
|
|
||||||
// making a background request looks good.
|
|
||||||
staleTime: 0,
|
|
||||||
|
|
||||||
// Refreshing when focus returns can be useful if a user comes back
|
|
||||||
// to the UI after performing an operation in the terminal.
|
|
||||||
refetchOnWindowFocus: true,
|
|
||||||
|
|
||||||
// Throw the error to the error boundary
|
|
||||||
throwOnError: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isPending) {
|
if (isPending) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -38,6 +38,11 @@
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.onboarding-codex {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes rotate {
|
@keyframes rotate {
|
||||||
from {
|
from {
|
||||||
transform: rotate(0deg); /* Start at 0 degrees */
|
transform: rotate(0deg); /* Start at 0 degrees */
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import "./OnBoardingStepThree.css";
|
|||||||
import { usePortForwarding } from "../../hooks/usePortForwarding";
|
import { usePortForwarding } from "../../hooks/usePortForwarding";
|
||||||
import { useCodexConnection } from "../../hooks/useCodexConnection";
|
import { useCodexConnection } from "../../hooks/useCodexConnection";
|
||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
ButtonIcon,
|
ButtonIcon,
|
||||||
Input,
|
Input,
|
||||||
SimpleText,
|
SimpleText,
|
||||||
@ -12,28 +13,33 @@ import { useEffect, useState } from "react";
|
|||||||
import { CodexSdk } from "../../sdk/codex";
|
import { CodexSdk } from "../../sdk/codex";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { usePersistence } from "../../hooks/usePersistence";
|
import { usePersistence } from "../../hooks/usePersistence";
|
||||||
|
import { useDebug } from "../../hooks/useDebug";
|
||||||
|
import { DebugUtils } from "../../utils/debug";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
online: boolean;
|
online: boolean;
|
||||||
onStepValid: (valid: boolean) => void;
|
onStepValid: (valid: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const throwOnError = false;
|
||||||
|
const defaultPort = 8070;
|
||||||
|
|
||||||
export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
||||||
const portForwarding = usePortForwarding(online);
|
const codex = useDebug(throwOnError);
|
||||||
const codex = useCodexConnection();
|
const portForwarding = usePortForwarding(codex.data);
|
||||||
const persistence = usePersistence(codex.enabled);
|
const persistence = usePersistence(codex.isSuccess);
|
||||||
const [url, setUrl] = useState(CodexSdk.url);
|
const [url, setUrl] = useState(CodexSdk.url);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onStepValid(online && portForwarding.enabled && codex.enabled);
|
onStepValid(online && portForwarding.enabled && codex.isSuccess);
|
||||||
}, [portForwarding.enabled, codex.enabled, onStepValid, online]);
|
}, [portForwarding.enabled, codex.isSuccess, onStepValid, online]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (codex.enabled) {
|
if (codex.isSuccess) {
|
||||||
persistence.refetch();
|
persistence.refetch();
|
||||||
}
|
}
|
||||||
}, [codex.enabled]);
|
}, [codex.isSuccess]);
|
||||||
|
|
||||||
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
|
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||||
const value = e.currentTarget.value;
|
const value = e.currentTarget.value;
|
||||||
@ -49,9 +55,22 @@ export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
|||||||
|
|
||||||
const InternetIcon = online ? CheckIcon : X;
|
const InternetIcon = online ? CheckIcon : X;
|
||||||
const PortForWarningIcon = portForwarding.enabled ? CheckIcon : X;
|
const PortForWarningIcon = portForwarding.enabled ? CheckIcon : X;
|
||||||
const CodexIcon = codex.enabled ? CheckIcon : X;
|
const CodexIcon = codex.isSuccess ? CheckIcon : X;
|
||||||
const PersistenceIcon = persistence.enabled ? CheckIcon : ShieldAlert;
|
const PersistenceIcon = persistence.enabled ? CheckIcon : ShieldAlert;
|
||||||
|
|
||||||
|
let hasPortForwarningWarning = false;
|
||||||
|
let portValue = 0;
|
||||||
|
|
||||||
|
if (codex.isSuccess && codex.data) {
|
||||||
|
const port = DebugUtils.getTcpPort(codex.data);
|
||||||
|
if (port.error === false && port.data !== defaultPort) {
|
||||||
|
hasPortForwarningWarning = true;
|
||||||
|
}
|
||||||
|
if (!port.error) {
|
||||||
|
portValue = port.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="index-column-section">
|
<div className="index-column-section">
|
||||||
<div className="onboarding-group">
|
<div className="onboarding-group">
|
||||||
@ -102,6 +121,14 @@ export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
|||||||
<SimpleText variant="light">
|
<SimpleText variant="light">
|
||||||
Status indicator for port forwarding activation.
|
Status indicator for port forwarding activation.
|
||||||
</SimpleText>
|
</SimpleText>
|
||||||
|
{portValue && (
|
||||||
|
<>
|
||||||
|
<br />
|
||||||
|
<SimpleText variant="light">
|
||||||
|
TCP Port detected: {portValue}.
|
||||||
|
</SimpleText>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!portForwarding.enabled && (
|
{!portForwarding.enabled && (
|
||||||
<a
|
<a
|
||||||
@ -118,59 +145,72 @@ export function OnBoardingStepThree({ online, onStepValid }: Props) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<p>Codex</p>
|
||||||
className={classnames(
|
<div className="onboarding-codex">
|
||||||
["onboarding-check"],
|
<div
|
||||||
["onboarding-check--valid", codex.enabled]
|
|
||||||
)}>
|
|
||||||
<CodexIcon
|
|
||||||
className={classnames(
|
className={classnames(
|
||||||
["onboarding-check-icon--valid", codex.enabled],
|
["onboarding-check"],
|
||||||
["onboarding-check-icon--invalid", !codex.enabled]
|
["onboarding-check--valid", codex.isSuccess]
|
||||||
)}
|
)}>
|
||||||
/>
|
<CodexIcon
|
||||||
<div className="onboarding-check-line">
|
className={classnames(
|
||||||
<div>
|
["onboarding-check-icon--valid", codex.isSuccess],
|
||||||
<p>Codex connection</p>
|
["onboarding-check-icon--invalid", !codex.isSuccess]
|
||||||
<SimpleText variant="light">
|
)}
|
||||||
Status indicator for the Codex network.
|
/>
|
||||||
</SimpleText>
|
<div className="onboarding-check-line">
|
||||||
|
<div>
|
||||||
|
<p>Codex connection</p>
|
||||||
|
<SimpleText variant="light">
|
||||||
|
Status indicator for the Codex network.
|
||||||
|
</SimpleText>
|
||||||
|
</div>
|
||||||
|
{!persistence.enabled && (
|
||||||
|
<a
|
||||||
|
className="onboarding-check-refresh"
|
||||||
|
onClick={() => persistence.refetch()}>
|
||||||
|
<RefreshCcw
|
||||||
|
size={"1.25rem"}
|
||||||
|
className={classnames([
|
||||||
|
"onboarding-check-refresh--fetching",
|
||||||
|
persistence.isFetching,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!persistence.enabled && (
|
|
||||||
<a
|
|
||||||
className="onboarding-check-refresh"
|
|
||||||
onClick={() => persistence.refetch()}>
|
|
||||||
<RefreshCcw
|
|
||||||
size={"1.25rem"}
|
|
||||||
className={classnames([
|
|
||||||
"onboarding-check-refresh--fetching",
|
|
||||||
persistence.isFetching,
|
|
||||||
])}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
["onboarding-check"],
|
|
||||||
["onboarding-check--valid", persistence.enabled]
|
|
||||||
)}>
|
|
||||||
<PersistenceIcon
|
|
||||||
className={classnames(
|
className={classnames(
|
||||||
["onboarding-check-icon--valid", persistence.enabled],
|
["onboarding-check"],
|
||||||
["onboarding-check-icon--warning", !persistence.enabled]
|
["onboarding-check--valid", persistence.enabled]
|
||||||
)}
|
)}>
|
||||||
/>
|
<PersistenceIcon
|
||||||
<div className="onboarding-check-line">
|
className={classnames(
|
||||||
<div>
|
["onboarding-check-icon--valid", persistence.enabled],
|
||||||
<p>Marketplace</p>
|
["onboarding-check-icon--warning", !persistence.enabled]
|
||||||
<SimpleText variant="light">
|
)}
|
||||||
Status indicator for the marketplace on the Codex node.
|
/>
|
||||||
</SimpleText>
|
<div className="onboarding-check-line">
|
||||||
|
<div>
|
||||||
|
<p>Marketplace</p>
|
||||||
|
<SimpleText variant="light">
|
||||||
|
Status indicator for the marketplace on the Codex node.
|
||||||
|
</SimpleText>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{hasPortForwarningWarning && (
|
||||||
|
<Alert variant="warning" title="Warning">
|
||||||
|
<span>
|
||||||
|
It seems like you are using a different port than the default one (
|
||||||
|
{defaultPort}). Be sure the port forwarning is enabled for the port
|
||||||
|
you are running.
|
||||||
|
</span>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/hooks/useDebug.ts
Normal file
31
src/hooks/useDebug.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { CodexSdk } from "../sdk/codex";
|
||||||
|
import { Promises } from "../utils/promises";
|
||||||
|
|
||||||
|
export function useDebug(throwOnError: boolean) {
|
||||||
|
const { data, isError, isPending, refetch, isSuccess } = useQuery({
|
||||||
|
queryFn: () =>
|
||||||
|
CodexSdk.debug()
|
||||||
|
.info()
|
||||||
|
.then((s) => Promises.rejectOnError(s)),
|
||||||
|
|
||||||
|
queryKey: ["debug"],
|
||||||
|
|
||||||
|
// No need to retry because if the connection to the node
|
||||||
|
// is back again, all the queries will be invalidated.
|
||||||
|
retry: false,
|
||||||
|
|
||||||
|
// The client node should be local, so display the cache value while
|
||||||
|
// making a background request looks good.
|
||||||
|
staleTime: 0,
|
||||||
|
|
||||||
|
// Refreshing when focus returns can be useful if a user comes back
|
||||||
|
// to the UI after performing an operation in the terminal.
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
|
||||||
|
// Throw the error to the error boundary
|
||||||
|
throwOnError,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, isPending, isError, isSuccess, refetch };
|
||||||
|
}
|
||||||
@ -1,19 +1,28 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { Echo } from "../utils/echo";
|
import { Echo } from "../utils/echo";
|
||||||
import { Errors } from "../utils/errors";
|
import { Errors } from "../utils/errors";
|
||||||
|
import { CodexDebugInfo } from "@codex-storage/sdk-js";
|
||||||
|
import { DebugUtils } from "../utils/debug";
|
||||||
|
|
||||||
type PortForwardingResponse = { reachable: boolean };
|
type PortForwardingResponse = { reachable: boolean };
|
||||||
|
|
||||||
export function usePortForwarding(online: boolean) {
|
export function usePortForwarding(info: CodexDebugInfo | undefined) {
|
||||||
const { data, isFetching, refetch } = useQuery({
|
const { data, isFetching, refetch } = useQuery({
|
||||||
queryFn: (): Promise<PortForwardingResponse> =>
|
queryFn: (): Promise<PortForwardingResponse> => {
|
||||||
Echo.portForwarding().catch((e) => Errors.report(e)),
|
const port = DebugUtils.getTcpPort(info!);
|
||||||
|
if (port.error) {
|
||||||
|
Errors.report(port);
|
||||||
|
return Promise.resolve({ reachable: false });
|
||||||
|
} else {
|
||||||
|
return Echo.portForwarding(port.data).catch((e) => Errors.report(e));
|
||||||
|
}
|
||||||
|
},
|
||||||
queryKey: ["port-forwarding"],
|
queryKey: ["port-forwarding"],
|
||||||
|
|
||||||
initialData: { reachable: false },
|
initialData: { reachable: false },
|
||||||
|
|
||||||
// Enable only when the use has an internet connection
|
// Enable only when the use has an internet connection
|
||||||
enabled: !!online,
|
enabled: !!info,
|
||||||
|
|
||||||
// No need to retry because we provide a retry button
|
// No need to retry because we provide a retry button
|
||||||
retry: false,
|
retry: false,
|
||||||
|
|||||||
@ -138,6 +138,10 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.index-column-section {
|
||||||
|
max-width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
.index-column-section:not(:first-child) {
|
.index-column-section:not(:first-child) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { OnBoardingStepThree } from "../components/OnBoarding/OnBoardingStepThre
|
|||||||
import { attributes } from "../utils/attributes";
|
import { attributes } from "../utils/attributes";
|
||||||
import { CodexLogo } from "../components/CodexLogo/CodexLogo";
|
import { CodexLogo } from "../components/CodexLogo/CodexLogo";
|
||||||
import { OnBoardingImage } from "../components/OnBoarding/OnBoardingImage";
|
import { OnBoardingImage } from "../components/OnBoarding/OnBoardingImage";
|
||||||
|
import { OnBoardingUtils } from "../utils/onboarding";
|
||||||
|
|
||||||
export const Route = createFileRoute("/")({
|
export const Route = createFileRoute("/")({
|
||||||
component: Index,
|
component: Index,
|
||||||
@ -24,7 +25,7 @@ export const Route = createFileRoute("/")({
|
|||||||
|
|
||||||
function Index() {
|
function Index() {
|
||||||
const [isStepValid, setIsStepValid] = useState(true);
|
const [isStepValid, setIsStepValid] = useState(true);
|
||||||
const [step, setStep] = useState(0);
|
const [step, setStep] = useState(OnBoardingUtils.getStep());
|
||||||
const online = useNetwork();
|
const online = useNetwork();
|
||||||
const navigate = useNavigate({ from: "/" });
|
const navigate = useNavigate({ from: "/" });
|
||||||
const onStepValid = (valid: boolean) => setIsStepValid(valid);
|
const onStepValid = (valid: boolean) => setIsStepValid(valid);
|
||||||
@ -39,6 +40,8 @@ function Index() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnBoardingUtils.setStep(step + 1);
|
||||||
|
|
||||||
setStep(step + 1);
|
setStep(step + 1);
|
||||||
setIsStepValid(false);
|
setIsStepValid(false);
|
||||||
};
|
};
|
||||||
|
|||||||
23
src/utils/debug.ts
Normal file
23
src/utils/debug.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { CodexDebugInfo, CodexError, SafeValue } from "@codex-storage/sdk-js";
|
||||||
|
|
||||||
|
export const DebugUtils = {
|
||||||
|
getTcpPort(info: CodexDebugInfo): SafeValue<number> {
|
||||||
|
if (info.addrs.length === 0) {
|
||||||
|
return { error: true, data: new CodexError("Not existing address") }
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = info.addrs[0].split("/")
|
||||||
|
|
||||||
|
if (parts.length < 2) {
|
||||||
|
return { error: true, data: new CodexError("Address misformated") }
|
||||||
|
}
|
||||||
|
|
||||||
|
const port = parseInt(parts[parts.length - 1], 10)
|
||||||
|
|
||||||
|
if (isNaN(port)) {
|
||||||
|
return { error: true, data: new CodexError("Port misformated") }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { error: false, data: port }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
export const Echo = {
|
export const Echo = {
|
||||||
portForwarding: () => fetch(import.meta.env.VITE_GEO_IP_URL + "/port/8070")
|
portForwarding: (port: number) => fetch(import.meta.env.VITE_GEO_IP_URL + "/port/" + port)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
|
|
||||||
}
|
}
|
||||||
9
src/utils/onboarding.ts
Normal file
9
src/utils/onboarding.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const OnBoardingUtils = {
|
||||||
|
getStep() {
|
||||||
|
return parseInt(localStorage.getItem("onboarding-step") || "0", 10)
|
||||||
|
},
|
||||||
|
|
||||||
|
setStep(step: number) {
|
||||||
|
localStorage.setItem("onboarding-step", step.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user