mirror of
https://github.com/Lissy93/web-check.git
synced 2025-05-17 20:50:46 +02:00
118 lines
4.4 KiB
TypeScript
118 lines
4.4 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { toast } from 'react-toastify';
|
|
import 'react-toastify/dist/ReactToastify.css';
|
|
|
|
import type { LoadingState } from 'web-check-live/components/misc/ProgressBar';
|
|
import type { AddressType } from 'web-check-live/utils/address-type-checker';
|
|
import keys from 'web-check-live/utils/get-keys';
|
|
|
|
interface UseIpAddressProps<ResultType = any> {
|
|
// Unique identifier for this job type
|
|
jobId: string | string[];
|
|
// The actual fetch request
|
|
fetchRequest: () => Promise<ResultType>;
|
|
// Function to call to update the loading state in parent
|
|
updateLoadingJobs: (job: string | string[], newState: LoadingState, error?: string, retry?: (data?: any) => void | null, data?: any) => void;
|
|
addressInfo: {
|
|
// The hostname/ip address that we're checking
|
|
address: string | undefined;
|
|
// The type of address (e.g. url, ipv4)
|
|
addressType: AddressType;
|
|
// The valid address types for this job
|
|
expectedAddressTypes: AddressType[];
|
|
};
|
|
}
|
|
|
|
type ResultType = any;
|
|
|
|
type ReturnType = [ResultType | undefined, (data?: any) => void];
|
|
|
|
const useMotherOfAllHooks = <ResultType = any>(params: UseIpAddressProps<ResultType>): ReturnType => {
|
|
// Destructure params
|
|
const { addressInfo, fetchRequest, jobId, updateLoadingJobs } = params;
|
|
const { address, addressType, expectedAddressTypes } = addressInfo;
|
|
|
|
// Build useState that will be returned
|
|
const [result, setResult] = useState<ResultType>();
|
|
|
|
// Fire off the HTTP fetch request, then set results and update loading / error state
|
|
|
|
const doTheFetch = () => {
|
|
if (keys.disableEverything) {
|
|
updateLoadingJobs(jobId, 'skipped', 'Web-Check is temporarily disabled. Please try again later.', reset);
|
|
return Promise.resolve();
|
|
}
|
|
return fetchRequest()
|
|
.then((res: any) => {
|
|
if (!res) { // No response :(
|
|
updateLoadingJobs(jobId, 'error', 'No response', reset);
|
|
} else if (res.error) { // Response returned an error message
|
|
if (res.error.includes("timed-out")) { // Specific handling for timeout errors
|
|
updateLoadingJobs(jobId, 'timed-out', res.error, reset);
|
|
} else {
|
|
updateLoadingJobs(jobId, 'error', res.error, reset);
|
|
}
|
|
} else if (res.errorType && res.errorMessage) {
|
|
const errorMessage = `${res.errorType}\n${res.errorMessage}\n\n`
|
|
+ `This sometimes occurs on Netlify if using the free plan. You may need to upgrade to use lambda functions`;
|
|
updateLoadingJobs(jobId, 'error', errorMessage, reset);
|
|
} else if (res.skipped) { // Response returned a skipped message
|
|
updateLoadingJobs(jobId, 'skipped', res.skipped, reset);
|
|
} else { // Yay, everything went to plan :)
|
|
setResult(res);
|
|
updateLoadingJobs(jobId, 'success', '', undefined, res);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
// Something fucked up
|
|
updateLoadingJobs(jobId, 'error', err.error || err.message || 'Unknown error', reset);
|
|
throw err;
|
|
})
|
|
}
|
|
|
|
// For when the user manually re-triggers the job
|
|
const reset = (data: any) => {
|
|
// If data is provided, then update state
|
|
if (data && !(data instanceof Event) && !data?._reactName) {
|
|
setResult(data);
|
|
} else { // Otherwise, trigger a data re-fetch
|
|
updateLoadingJobs(jobId, 'loading');
|
|
const fetchyFetch = doTheFetch();
|
|
const toastOptions = {
|
|
pending: `Updating Data (${jobId})`,
|
|
success: `Completed (${jobId})`,
|
|
error: `Failed to update (${jobId})`,
|
|
skipped: `Skipped job (${jobId}), as no valid results for host`,
|
|
};
|
|
// Initiate fetch, and show progress toast
|
|
toast.promise(fetchyFetch, toastOptions).catch(() => {});
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
// Still waiting for this upstream, cancel job
|
|
if (!address || !addressType) {
|
|
return;
|
|
}
|
|
// This job isn't needed for this address type, cancel job
|
|
if (!expectedAddressTypes.includes(addressType)) {
|
|
if (addressType !== 'empt') updateLoadingJobs(jobId, 'skipped');
|
|
return;
|
|
}
|
|
|
|
// Initiate the data fetching process
|
|
doTheFetch().catch(() => {});
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [address, addressType]);
|
|
|
|
return [result, reset];
|
|
};
|
|
|
|
export default useMotherOfAllHooks;
|
|
|
|
// I really fucking hate TypeScript sometimes....
|
|
// Feels like a weak attempt at trying to make JavaScript less crappy,
|
|
// when the real solution would be to just switch to a proper, typed, safe language
|
|
// ... Either that, or I'm just really shit at it.
|