Add metadata to ParsedGeneric submit response

This commit is contained in:
2024-05-10 05:42:43 -05:00
parent 670e8c377a
commit 597863ea70
2 changed files with 50 additions and 41 deletions

View File

@@ -23,6 +23,11 @@ import type { ParsedGeneric } from "@/components/lookup/Generic";
import { Maybe, Result } from "true-myth"; import { Maybe, Result } from "true-myth";
export type WarningHandler = (warning: { message: string }) => void; export type WarningHandler = (warning: { message: string }) => void;
export type MetaParsedGeneric = {
data: ParsedGeneric;
url: string;
completeTime: Date;
};
const useLookup = (warningHandler?: WarningHandler) => { const useLookup = (warningHandler?: WarningHandler) => {
/** /**
@@ -30,7 +35,7 @@ const useLookup = (warningHandler?: WarningHandler) => {
* This uses TargetType as the key, meaning v4/v6 IP/CIDR lookups are differentiated. * This uses TargetType as the key, meaning v4/v6 IP/CIDR lookups are differentiated.
*/ */
const registryDataRef = useRef<Record<RootRegistryType, Register | null>>( const registryDataRef = useRef<Record<RootRegistryType, Register | null>>(
{} as Record<RootRegistryType, Register> {} as Record<RootRegistryType, Register>
); );
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -41,14 +46,10 @@ const useLookup = (warningHandler?: WarningHandler) => {
// Used to allow repeatable lookups when weird errors happen. // Used to allow repeatable lookups when weird errors happen.
const repeatableRef = useRef<string>(""); const repeatableRef = useRef<string>("");
/** */
const uriType = useMemo<Maybe<TargetType>>( const uriType = useMemo<Maybe<TargetType>>(
function () { function () {
if (currentType != null) return Maybe.just(currentType); if (currentType != null) return Maybe.just(currentType);
return getType(target).mapOr( return getType(target).mapOr(Maybe.nothing(), (type) => Maybe.just(type));
Maybe.nothing(),
(type) => Maybe.just(type)
);
}, },
[target, currentType] [target, currentType]
); );
@@ -158,18 +159,22 @@ const useLookup = (warningHandler?: WarningHandler) => {
if (result.success === false) { if (result.success === false) {
// flatten the errors to make them more readable and simple // flatten the errors to make them more readable and simple
const flatErrors = result.error.flatten(function (issue) { const flatErrors = result.error.flatten(function (issue) {
const path = issue.path.map((value => value.toString())).join('.'); const path = issue.path.map((value) => value.toString()).join(".");
return `${path}: ${issue.message}`; return `${path}: ${issue.message}`;
}); });
console.log(flatErrors); console.log(flatErrors);
// combine them all, wrap them in a new error, and return it // combine them all, wrap them in a new error, and return it
return Result.err(new Error([ return Result.err(
"Could not parse the response from the registry.", new Error(
...flatErrors.formErrors, [
...Object.values(flatErrors.fieldErrors).flat(), "Could not parse the response from the registry.",
].join('\n\t'))); ...flatErrors.formErrors,
...Object.values(flatErrors.fieldErrors).flat(),
].join("\n\t")
)
);
} }
return Result.ok(result.data); return Result.ok(result.data);
@@ -216,7 +221,9 @@ const useLookup = (warningHandler?: WarningHandler) => {
} }
} }
async function submitInternal(target: string): Promise<Result<ParsedGeneric, Error>> { async function submitInternal(
target: string
): Promise<Result<{data: ParsedGeneric, url: string}, Error>> {
if (target == null || target.length == 0) if (target == null || target.length == 0)
return Result.err( return Result.err(
new Error("A target must be given in order to execute a lookup.") new Error("A target must be given in order to execute a lookup.")
@@ -238,17 +245,15 @@ const useLookup = (warningHandler?: WarningHandler) => {
await loadBootstrap("ip4"); await loadBootstrap("ip4");
const url = getRegistryURL(targetType.value, target); const url = getRegistryURL(targetType.value, target);
const result = await getAndParse<IpNetwork>(url, IpNetworkSchema); const result = await getAndParse<IpNetwork>(url, IpNetworkSchema);
if (result.isErr) if (result.isErr) return Result.err(result.error);
return Result.err(result.error); return Result.ok({data: result.value, url});
return Result.ok(result.value);
} }
case "ip6": { case "ip6": {
await loadBootstrap("ip6"); await loadBootstrap("ip6");
const url = getRegistryURL(targetType.value, target); const url = getRegistryURL(targetType.value, target);
const result = await getAndParse<IpNetwork>(url, IpNetworkSchema); const result = await getAndParse<IpNetwork>(url, IpNetworkSchema);
if (result.isErr) if (result.isErr) return Result.err(result.error);
return Result.err(result.error); return Result.ok({data: result.value, url});
return Result.ok(result.value);
} }
case "domain": { case "domain": {
await loadBootstrap("domain"); await loadBootstrap("domain");
@@ -266,10 +271,9 @@ const useLookup = (warningHandler?: WarningHandler) => {
); );
} }
const result = await getAndParse<Domain>(url, DomainSchema); const result = await getAndParse<Domain>(url, DomainSchema);
if (result.isErr) if (result.isErr) return Result.err(result.error);
return Result.err(result.error);
return Result.ok(result.value); return Result.ok({data: result.value, url});
} }
case "autnum": { case "autnum": {
await loadBootstrap("autnum"); await loadBootstrap("autnum");
@@ -278,9 +282,8 @@ const useLookup = (warningHandler?: WarningHandler) => {
url, url,
AutonomousNumberSchema AutonomousNumberSchema
); );
if (result.isErr) if (result.isErr) return Result.err(result.error);
return Result.err(result.error); return Result.ok({data: result.value, url});
return Result.ok(result.value);
} }
case "url": case "url":
case "tld": case "tld":
@@ -295,7 +298,7 @@ const useLookup = (warningHandler?: WarningHandler) => {
async function submit({ async function submit({
target, target,
}: SubmitProps): Promise<Maybe<ParsedGeneric>> { }: SubmitProps): Promise<Maybe<MetaParsedGeneric>> {
try { try {
// target is already set in state, but it's also provided by the form callback, so we'll use it. // target is already set in state, but it's also provided by the form callback, so we'll use it.
const response = await submitInternal(target); const response = await submitInternal(target);
@@ -303,15 +306,19 @@ const useLookup = (warningHandler?: WarningHandler) => {
if (response.isErr) { if (response.isErr) {
setError(response.error.message); setError(response.error.message);
console.error(response.error); console.error(response.error);
} } else setError(null);
else setError(null);
return response.isOk ? Maybe.just(response.value) : Maybe.nothing(); return response.isOk ? Maybe.just(
{
data: response.value.data,
url: response.value.url,
completeTime: new Date(),
}
) : Maybe.nothing();
} catch (e) { } catch (e) {
if (!(e instanceof Error)) if (!(e instanceof Error))
setError("An unknown, unprocessable error has occurred."); setError("An unknown, unprocessable error has occurred.");
else else setError(e.message);
setError(e.message);
console.error(e); console.error(e);
return Maybe.nothing(); return Maybe.nothing();
} }

View File

@@ -1,7 +1,8 @@
import { type NextPage } from "next"; import { type NextPage } from "next";
import Head from "next/head"; import Head from "next/head";
import { useState } from "react"; import { useState } from "react";
import Generic, { type ParsedGeneric } from "@/components/lookup/Generic"; import Generic from "@/components/lookup/Generic";
import type { MetaParsedGeneric } from "@/hooks/useLookup";
import useLookup from "@/hooks/useLookup"; import useLookup from "@/hooks/useLookup";
import { OGP } from "react-ogp"; import { OGP } from "react-ogp";
import LookupInput from "@/components/form/LookupInput"; import LookupInput from "@/components/form/LookupInput";
@@ -12,8 +13,10 @@ import { getType } from "@/rdap";
const Index: NextPage = () => { const Index: NextPage = () => {
const { error, setTarget, setTargetType, submit } = useLookup(); const { error, setTarget, setTargetType, submit } = useLookup();
const [detectedType, setDetectedType] = useState<Maybe<TargetType>>(Maybe.nothing()); const [detectedType, setDetectedType] = useState<Maybe<TargetType>>(
const [response, setResponse] = useState<ParsedGeneric | null>(); Maybe.nothing()
);
const [response, setResponse] = useState<Maybe<MetaParsedGeneric>>(Maybe.nothing());
const [isLoading, setLoading] = useState<boolean>(false); const [isLoading, setLoading] = useState<boolean>(false);
return ( return (
@@ -59,14 +62,11 @@ const Index: NextPage = () => {
onSubmit={async function (props) { onSubmit={async function (props) {
try { try {
setLoading(true); setLoading(true);
const result = await submit(props); setResponse(await submit(props));
if (result.isJust)
setResponse(result.value);
else
setResponse(null);
setLoading(false); setLoading(false);
} catch (e) { } catch (e) {
setResponse(null); console.error(e);
setResponse(Maybe.nothing());
setLoading(false); setLoading(false);
} }
}} }}
@@ -78,7 +78,9 @@ const Index: NextPage = () => {
className="mb-2" className="mb-2"
/> />
) : null} ) : null}
{response != null ? <Generic url={"https://google.com"} data={response} /> : null} {response.isJust ? (
<Generic url={response.value.url} data={response.value.data} />
) : null}
</div> </div>
</div> </div>
</> </>