From 60999749fabfeebb31a4289a138cfc20fcb72280 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Fri, 10 May 2024 23:04:39 +1200 Subject: [PATCH] add support for downloading files from nomadnet nodes --- public/index.html | 91 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/public/index.html b/public/index.html index 2555538..38a04b4 100644 --- a/public/index.html +++ b/public/index.html @@ -493,6 +493,17 @@

                 
 
+                
+                
+
+ + + + +
+
Downloading: {{ nodeFilePath }} ({{ nodeFileProgress }}%)
+
+ @@ -542,6 +553,10 @@ nodePageContent: null, nodePageProgress: 0, + isDownloadingNodeFile: false, + nodeFilePath: null, + nodeFileProgress: 0, + nomadnetPageDownloadCallbacks: {}, nomadnetFileDownloadCallbacks: {}, @@ -1120,15 +1135,48 @@ const parsedUrl = this.parseNomadnetworkUrl(url); if(parsedUrl != null){ - // file urls are not supported yet - if(parsedUrl.path.startsWith("/file/")){ - alert("file urls are not supported yet") - return; - } - // use parsed destination hash, or fallback to selected node destination hash const destinationHash = parsedUrl.destination_hash || this.selectedNode.destination_hash; + // download file + if(parsedUrl.path.startsWith("/file/")){ + + // prevent simultaneous downloads + if(this.isDownloadingNodeFile){ + alert("An existing download is in progress. Please wait for it to finish beforing starting another download."); + return; + } + + // update ui + this.isDownloadingNodeFile = true; + this.nodeFilePath = parsedUrl.path.split("/").pop(); + this.nodeFileProgress = 0; + + // start file download + this.downloadNomadNetFile(destinationHash, parsedUrl.path, (fileName, fileBytesBase64) => { + + // no longer downloading + this.isDownloadingNodeFile = false; + + // download file to browser + this.downloadFileFromBase64(fileName, fileBytesBase64); + + }, (failureReason) => { + + // no longer downloading + this.isDownloadingNodeFile = false; + + // show error message + alert(`Failed to download file: ${failureReason}`); + + }, (progress) => { + this.nodeFileProgress = Math.round(progress * 100); + }); + + return; + + } + // update selected node, so relative urls work correctly when returned by the new node this.selectedNode = this.nodes[destinationHash] || { name: "Unknown Node", @@ -1199,6 +1247,37 @@ // open new tab window.open(fileUrl); + }, + downloadFileFromBase64: async function(fileName, fileBytesBase64) { + + // create blob from base64 encoded file bytes + const byteCharacters = atob(fileBytesBase64); + const byteNumbers = new Array(byteCharacters.length); + for(let i = 0; i < byteCharacters.length; i++){ + byteNumbers[i] = byteCharacters.charCodeAt(i); + } + const byteArray = new Uint8Array(byteNumbers); + const blob = new Blob([byteArray]); + + // create object url for blob + const objectUrl = URL.createObjectURL(blob); + + // create link element to download blob + const link = document.createElement('a'); + link.href = objectUrl; + link.download = fileName; + link.style.display = "none"; + document.body.append(link); + + // click link to download file in browser + link.click(); + + // link element is no longer needed + link.remove(); + + // revoke object url to clear memory + setTimeout(() => URL.revokeObjectURL(objectUrl), 10000); + }, onPeerClick: function(peer) { this.selectedNode = null;