Directory Upload & Auto UUID (#60)
This commit is contained in:
parent
f4760e4481
commit
96034cf10d
|
@ -19,6 +19,7 @@
|
|||
"gatsby-transformer-sharp": "^2.3.17",
|
||||
"jsonp": "^0.2.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.0",
|
||||
"react-countup": "^4.3.3",
|
||||
|
@ -29,8 +30,7 @@
|
|||
"react-mailchimp-subscribe": "^2.1.0",
|
||||
"react-reveal": "^1.2.2",
|
||||
"react-syntax-highlighter": "^12.2.1",
|
||||
"react-visibility-sensor": "^5.1.1",
|
||||
"shortid": "^2.2.15"
|
||||
"react-visibility-sensor": "^5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cypress": "^4.1.0",
|
||||
|
|
|
@ -10,6 +10,11 @@ server {
|
|||
listen [::]:443 ssl http2;
|
||||
server_name siasky.net www.siasky.net; # replace with actual server names
|
||||
|
||||
# Enable the following line if you want to have auto uuid support. This
|
||||
# means users are able to upload Skyfiles without having to provide a uuid
|
||||
# themselves.
|
||||
# rewrite ^/skynet/skyfile/?$ /skynet/skyfile/$request_id$1;
|
||||
|
||||
# NOTE: make sure to enable any additional configuration you might need like gzip
|
||||
|
||||
location / {
|
||||
|
@ -32,10 +37,11 @@ server {
|
|||
proxy_set_header Authorization "Basic BASE64_AUTHENTICATION";
|
||||
}
|
||||
|
||||
location ~ "^/([a-zA-Z0-9-_]{46})$" {
|
||||
location ~ "^/([a-zA-Z0-9-_]{46}(/.*)?)$" {
|
||||
proxy_read_timeout 600;
|
||||
# proxy this call to siad /skynet/skylink/ endpoint (make sure the ip is correct)
|
||||
proxy_pass http://127.0.0.1:9980/skynet/skylink/$1;
|
||||
# proxy this call to siad /skynet/skylink/ endpoint (make sure the ip is
|
||||
# correct)
|
||||
proxy_pass http://127.0.0.1:9980/skynet/skylink/$1$is_args$args;
|
||||
proxy_set_header Access-Control-Allow-Origin: *;
|
||||
# make sure to override user agent header - siad requirement
|
||||
proxy_set_header User-Agent: Sia-Agent;
|
||||
|
@ -45,11 +51,12 @@ server {
|
|||
#proxy_buffers 4 128k;
|
||||
}
|
||||
|
||||
location ~ "^/file/([a-zA-Z0-9-_]{46})$" {
|
||||
location ~ "^/file/([a-zA-Z0-9-_]{46}(/.*)?)$" {
|
||||
proxy_read_timeout 600;
|
||||
# proxy this call to siad /skunet/skylink/ endpoint (make sure the ip is correct)
|
||||
# this alias also adds attachment=true url param to force download the file
|
||||
proxy_pass http://127.0.0.1:9980/skynet/skylink/$1?attachment=true;
|
||||
# proxy this call to siad /skunet/skylink/ endpoint (make sure the ip is
|
||||
# correct) this alias also adds attachment=true url param to force
|
||||
# download the file
|
||||
proxy_pass http://127.0.0.1:9980/skynet/skylink/$1?attachment=true&$args;
|
||||
proxy_set_header Access-Control-Allow-Origin: *;
|
||||
# make sure to override user agent header - siad requirement
|
||||
proxy_set_header User-Agent: Sia-Agent;
|
||||
|
|
|
@ -9,7 +9,7 @@ Skynet.download_file("./dst.jpg", skylink)
|
|||
print("Download successful")`;
|
||||
|
||||
export const curl = `# upload
|
||||
curl -X POST "https://siasky.net/skynet/skyfile/[uuid]" -F file=@src.jpg
|
||||
curl -X POST "https://siasky.net/skynet/skyfile" -F file=@src.jpg
|
||||
|
||||
# download
|
||||
curl "https://siasky.net/[skylink]" -o dst.jpg`;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useState, useContext } from "react";
|
||||
import React, { useState, useContext, useEffect } from "react";
|
||||
import classNames from "classnames";
|
||||
import Dropzone from "react-dropzone";
|
||||
import path from "path-browserify";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import Reveal from "react-reveal/Reveal";
|
||||
import shortid from "shortid";
|
||||
import { Button, UploadFile } from "../";
|
||||
import { Deco3, Deco4, Deco5, Folder, DownArrow } from "../../svg";
|
||||
import "./HomeUpload.scss";
|
||||
|
@ -12,8 +12,47 @@ import axios from "axios";
|
|||
export default function HomeUpload() {
|
||||
const [files, setFiles] = useState([]);
|
||||
const { apiUrl } = useContext(AppContext);
|
||||
const [directoryMode, setDirectoryMode] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (directoryMode) {
|
||||
inputRef.current.setAttribute("webkitdirectory", "true");
|
||||
} else {
|
||||
inputRef.current.removeAttribute("webkitdirectory");
|
||||
}
|
||||
}, [directoryMode]);
|
||||
|
||||
const getFilePath = (file) => file.webkitRelativePath || file.path || file.name;
|
||||
|
||||
const getRelativeFilePath = (file) => {
|
||||
const filePath = getFilePath(file);
|
||||
const { root, dir, base } = path.parse(filePath);
|
||||
const relative = path
|
||||
.normalize(dir)
|
||||
.slice(root.length)
|
||||
.split(path.sep)
|
||||
.slice(1);
|
||||
|
||||
return path.join(...relative, base);
|
||||
};
|
||||
|
||||
const getRootDirectory = (file) => {
|
||||
const filePath = getFilePath(file);
|
||||
const { root, dir } = path.parse(filePath);
|
||||
|
||||
return path
|
||||
.normalize(dir)
|
||||
.slice(root.length)
|
||||
.split(path.sep)[0];
|
||||
};
|
||||
|
||||
const handleDrop = async (acceptedFiles) => {
|
||||
if (directoryMode && acceptedFiles.length) {
|
||||
const rootDir = getRootDirectory(acceptedFiles[0]); // get the file path from the first file
|
||||
|
||||
acceptedFiles = [{ name: rootDir, directory: true, files: acceptedFiles }];
|
||||
}
|
||||
|
||||
setFiles((previousFiles) => [...acceptedFiles.map((file) => ({ file, status: "uploading" })), ...previousFiles]);
|
||||
|
||||
const onFileStateChange = (file, state) => {
|
||||
|
@ -31,30 +70,45 @@ export default function HomeUpload() {
|
|||
});
|
||||
};
|
||||
|
||||
const onProgress = (file, { loaded, total }) => {
|
||||
const progress = loaded / total;
|
||||
const status = progress === 1 ? "processing" : "uploading";
|
||||
const upload = async (formData, directory, file) => {
|
||||
const uploadUrl = `${apiUrl}/skynet/skyfile/${directory ? `?filename=${encodeURIComponent(directory)}` : ""}`;
|
||||
const { data } = await axios.post(uploadUrl, formData, {
|
||||
onUploadProgress: ({ loaded, total }) => {
|
||||
const progress = loaded / total;
|
||||
const status = progress === 1 ? "processing" : "uploading";
|
||||
|
||||
onFileStateChange(file, { status, progress });
|
||||
onFileStateChange(file, { status, progress });
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
acceptedFiles.forEach(async (file) => {
|
||||
try {
|
||||
const fd = new FormData();
|
||||
fd.append("file", file);
|
||||
const formData = new FormData();
|
||||
|
||||
const uuid = shortid.generate();
|
||||
const { data } = await axios.post(`${apiUrl}/skynet/skyfile/${uuid}`, fd, {
|
||||
onUploadProgress: (event) => onProgress(file, event)
|
||||
});
|
||||
if (file.directory) {
|
||||
file.files.forEach((directoryFile) => {
|
||||
const relativeFilePath = getRelativeFilePath(directoryFile);
|
||||
|
||||
onFileStateChange(file, { status: "complete", url: `${apiUrl}/${data.skylink}` });
|
||||
formData.append("files[]", directoryFile, relativeFilePath);
|
||||
});
|
||||
} else {
|
||||
formData.append("file", file);
|
||||
}
|
||||
|
||||
const { skylink } = await upload(formData, directoryMode && file.name, file);
|
||||
|
||||
onFileStateChange(file, { status: "complete", url: `${apiUrl}/${skylink}` });
|
||||
} catch (error) {
|
||||
onFileStateChange(file, { status: "error" });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive, inputRef } = useDropzone({ onDrop: handleDrop });
|
||||
|
||||
const handleSkylink = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
|
@ -71,28 +125,44 @@ export default function HomeUpload() {
|
|||
<div className="home-upload-white fadeInUp delay4">
|
||||
<div className="home-upload-split">
|
||||
<div className="home-upload-box ">
|
||||
<Dropzone onDrop={handleDrop}>
|
||||
{({ getRootProps, getInputProps, isDragActive }) => (
|
||||
<>
|
||||
<div
|
||||
className={classNames("home-upload-dropzone", {
|
||||
"drop-active": isDragActive
|
||||
})}
|
||||
{...getRootProps()}
|
||||
>
|
||||
<span className="home-upload-text">
|
||||
<h3>Upload your Files</h3>
|
||||
Drop your files here to pin to Skynet
|
||||
</span>
|
||||
<Button iconLeft>
|
||||
<Folder />
|
||||
Browse
|
||||
</Button>
|
||||
</div>
|
||||
<input {...getInputProps()} className="offscreen" />
|
||||
</>
|
||||
)}
|
||||
</Dropzone>
|
||||
<div
|
||||
className={classNames("home-upload-dropzone", {
|
||||
"drop-active": isDragActive
|
||||
})}
|
||||
{...getRootProps()}
|
||||
>
|
||||
<span className="home-upload-text">
|
||||
<h3>Upload your {directoryMode ? "Directory" : "Files"}</h3>
|
||||
Drop your {directoryMode ? "directory" : "files"} here to pin to Skynet
|
||||
</span>
|
||||
<Button iconLeft>
|
||||
<Folder />
|
||||
Browse
|
||||
</Button>
|
||||
</div>
|
||||
<input {...getInputProps()} className="offscreen" />
|
||||
<button
|
||||
type="button"
|
||||
className="home-upload-mode-switch link"
|
||||
onClick={() => setDirectoryMode(!directoryMode)}
|
||||
>
|
||||
{directoryMode ? "⇐ Switch back to uploading files" : "Do you want to upload entire directory?"}
|
||||
</button>
|
||||
{directoryMode && (
|
||||
<p className="home-upload-directory-mode-notice">
|
||||
Please note that directory upload is not a standard browser feature and the browser support is
|
||||
limited. To check whether your browser is compatible, visit{" "}
|
||||
<a
|
||||
href="https://caniuse.com/#feat=mdn-api_htmlinputelement_webkitdirectory"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="link"
|
||||
>
|
||||
caniuse.com
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="home-upload-retrieve">
|
||||
|
|
|
@ -89,6 +89,24 @@
|
|||
}
|
||||
}
|
||||
|
||||
.home-upload-mode-switch {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
margin: 10px auto 0;
|
||||
|
||||
@media (min-width: $largebp) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.home-upload-directory-mode-notice {
|
||||
color: $lightGray;
|
||||
font-size: 13px;
|
||||
line-height: 1.2em;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.home-upload-text {
|
||||
color: $gray;
|
||||
display: block;
|
||||
|
|
|
@ -128,6 +128,15 @@ svg {
|
|||
color: $darkGray;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: $green;
|
||||
transition: 0.2s color;
|
||||
|
||||
&:hover {
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
.truncate {
|
||||
width: 250px;
|
||||
white-space: nowrap;
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -8492,11 +8492,6 @@ nan@^2.12.1, nan@^2.13.2, nan@^2.14.0:
|
|||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||
|
||||
nanoid@^2.1.0:
|
||||
version "2.1.11"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||
|
@ -9380,6 +9375,11 @@ path-browserify@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
|
||||
integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
|
||||
|
||||
path-browserify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
||||
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
|
||||
|
||||
path-dirname@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
|
||||
|
@ -11333,13 +11333,6 @@ shell-quote@1.6.1:
|
|||
array-reduce "~0.0.0"
|
||||
jsonify "~0.0.0"
|
||||
|
||||
shortid@^2.2.15:
|
||||
version "2.2.15"
|
||||
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
|
||||
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
|
||||
dependencies:
|
||||
nanoid "^2.1.0"
|
||||
|
||||
side-channel@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
|
||||
|
|
Reference in New Issue