From 67285ccc086d97cf395331a1e85e4c719afaf70a Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Sun, 31 Jul 2022 00:56:54 -0400 Subject: [PATCH] *add modified downloadSkylink that uses the trust-needed endpoint and supports a path on the skylink, but also provides the raw response object --- src/util.ts | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/util.ts b/src/util.ts index af6b94c..564052e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,3 +1,15 @@ +import { + addContextToErr, + b64ToBuf, + defaultPortalList, + Err, + objAsString, + progressiveFetch, + progressiveFetchResult, + validSkylink, + verifyDownloadResponse, +} from "libskynet"; + export function isIp(ip: string) { return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( ip @@ -21,3 +33,82 @@ export const requestProxies = [ { type: "http", host: "skynetfree.net", port: 80 }, { type: "http", host: "skynetpro.net", port: 80 }, ]; + +export function getTld(hostname: string): string { + return hostname.includes(".") + ? hostname.split(".")[hostname.split(".").length - 1] + : hostname; +} + +export type FileDataType = { + err: null; + response: Response | null; + fileData: Uint8Array; +}; + +export function downloadSkylink( + skylink: string, + path?: string +): Promise<[data: FileDataType, err: Err]> { + return new Promise((resolve) => { + // Get the Uint8Array of the input skylink. + let [u8Link, errBTB] = b64ToBuf(skylink); + if (errBTB !== null) { + resolve([{} as any, addContextToErr(errBTB, "unable to decode skylink")]); + return; + } + if (!validSkylink(u8Link)) { + resolve([{} as any, "skylink appears to be invalid"]); + return; + } + + // Prepare the download call. + let endpoint = "/" + skylink; + if (path) { + endpoint += path; + } + let fileDataPtr: FileDataType = { + fileData: new Uint8Array(0), + err: null, + response: null, + }; + let verifyFunction = function (response: Response): Promise { + return verifyDownloadResponse(response, u8Link, fileDataPtr); + }; + + // Perform the download call. + progressiveFetch(endpoint, null, defaultPortalList, () => + Promise.resolve(null) + ).then((result: progressiveFetchResult) => { + // Return an error if the call failed. + if (result.success !== true) { + // Check for a 404. + for (let i = 0; i < result.responsesFailed.length; i++) { + if (result.responsesFailed[i].status === 404) { + resolve([{} as any, "404"]); + return; + } + } + + // Error is not a 404, return the logs as the error. + let err = objAsString(result.logs); + resolve([ + {} as any, + addContextToErr(err, "unable to complete download"), + ]); + return; + } + // Check if the portal is honest but the download is corrupt. + if (fileDataPtr.err !== null) { + resolve([ + {} as any, + addContextToErr(fileDataPtr.err, "download is corrupt"), + ]); + return; + } + + fileDataPtr.response = result.response; + resolve([fileDataPtr, null]); + }); + }); +}