form upload
This commit is contained in:
parent
c5c7c7f809
commit
f9d3d8b7f3
|
@ -1,10 +1,10 @@
|
||||||
/** @jsx jsx */
|
/** @jsx jsx */
|
||||||
import * as R from "ramda"
|
import * as R from "ramda"
|
||||||
import { useCallback, useState } from "react"
|
import { useCallback, useState, useRef } from "react"
|
||||||
import { useDropzone } from "react-dropzone"
|
import { useDropzone } from "react-dropzone"
|
||||||
import { Box, Flex, jsx } from "theme-ui"
|
import { Box, Flex, jsx } from "theme-ui"
|
||||||
import { CircularProgress } from "@material-ui/core"
|
import { CircularProgress, Button } from "@material-ui/core"
|
||||||
|
import { saveAs } from "file-saver"
|
||||||
/**
|
/**
|
||||||
* nginx is setup to automatically handle and rewrite the url path.
|
* nginx is setup to automatically handle and rewrite the url path.
|
||||||
*/
|
*/
|
||||||
|
@ -18,83 +18,62 @@ const splitFilename = R.compose(R.head, R.split(".sia"))
|
||||||
function MyDropzone() {
|
function MyDropzone() {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
|
const formRef = useRef(null)
|
||||||
|
const inputRef = useRef(null)
|
||||||
|
|
||||||
const onDrop = useCallback(
|
const onDrop = useCallback(
|
||||||
acceptedFiles => {
|
acceptedFiles => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const file = R.head(acceptedFiles)
|
const file = R.head(acceptedFiles)
|
||||||
const fd = new FormData()
|
const fd = new FormData(formRef.current)
|
||||||
const fileName = R.compose(splitFilename, pName)(file)
|
const fileName = R.compose(splitFilename, pName)(file)
|
||||||
|
|
||||||
fd.append("file", file)
|
const url = API_ENDPOINT + "/siafile"
|
||||||
if (window) {
|
|
||||||
const streamSaver = require("streamsaver")
|
|
||||||
console.log("streamSaver", streamSaver)
|
|
||||||
const url = API_ENDPOINT + "/siafile"
|
|
||||||
fetch(url, {
|
|
||||||
method: "POST",
|
|
||||||
body: fd,
|
|
||||||
headers: {
|
|
||||||
"Access-Control-Allow-Origin": "*"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
if (!res.ok) {
|
|
||||||
setLoading(false)
|
|
||||||
setError(res.status + " " + res.statusText)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const readableStream = res.body
|
|
||||||
const fileStream = streamSaver.createWriteStream(fileName)
|
|
||||||
|
|
||||||
// more optimized
|
// formRef.current.submit()
|
||||||
if (window.WritableStream && readableStream.pipeTo) {
|
|
||||||
return readableStream.pipeTo(fileStream).then(() => {
|
// fetch(url, {
|
||||||
setLoading(false)
|
// method: "POST",
|
||||||
console.log("done writing")
|
// body: fd,
|
||||||
})
|
// credentials: "include"
|
||||||
}
|
// })
|
||||||
;(window as any).writer = fileStream.getWriter()
|
// .then(res => {
|
||||||
const reader = res.body.getReader()
|
// return res.headers
|
||||||
const pump = () =>
|
// })
|
||||||
reader
|
// .then(headers => {
|
||||||
.read()
|
// console.log("WE OUT HERE BOYS", document.cookie)
|
||||||
.then(res =>
|
// fetch(API_ENDPOINT + "/siafile/download", {
|
||||||
res.done
|
// credentials: "include"
|
||||||
? (window as any).writer.close()
|
// })
|
||||||
: (window as any).writer.write(res.value).then(pump)
|
// .then(res => res.blob())
|
||||||
)
|
// .then(blob => saveAs(blob, fileName))
|
||||||
.catch(e => {
|
// // saveAs(API_ENDPOINT + "/siafile/download", fileName)
|
||||||
setLoading(false)
|
// })
|
||||||
})
|
// .catch(e => {
|
||||||
pump()
|
// console.log("error is", e)
|
||||||
})
|
// setLoading(false)
|
||||||
.catch(e => {
|
// })
|
||||||
// setError(e)
|
|
||||||
console.log("error is", e)
|
|
||||||
setLoading(false)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[loading, setLoading, error, setError]
|
[loading, setLoading, error, setError, formRef]
|
||||||
)
|
)
|
||||||
|
|
||||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Flex
|
<Flex
|
||||||
{...getRootProps()}
|
|
||||||
sx={{ height: 400, justifyContent: "center", alignItems: "center" }}
|
sx={{ height: 400, justifyContent: "center", alignItems: "center" }}
|
||||||
>
|
>
|
||||||
<input {...getInputProps()} />
|
<form
|
||||||
{error && error}
|
id="hidden-form"
|
||||||
{!error &&
|
action={`${API_ENDPOINT}/siafile`}
|
||||||
(loading ? (
|
method="POST"
|
||||||
<CircularProgress color="secondary" />
|
encType="multipart/form-data"
|
||||||
) : isDragActive ? (
|
ref={formRef}
|
||||||
<p>Drop to 🚀 ...</p>
|
>
|
||||||
) : (
|
<input type="file" name="file" ref={inputRef} />
|
||||||
<p>Drag 'n' drop a Sia file here, or click to select a Sia file.</p>
|
<Button type="submit"> Download</Button>
|
||||||
))}
|
</form>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
"express-fileupload": "1.1.6",
|
"express-fileupload": "1.1.6",
|
||||||
|
"express-session": "1.17.0",
|
||||||
"ramda": "0.26.1",
|
"ramda": "0.26.1",
|
||||||
"typescript": "^3.5.2"
|
"typescript": "^3.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ramda": "0.26.36"
|
"@types/ramda": "0.26.36"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,16 +52,24 @@ export class Server {
|
||||||
private getPort = (): number => parseInt(process.env.PORT, 10) || 3000
|
private getPort = (): number => parseInt(process.env.PORT, 10) || 3000
|
||||||
|
|
||||||
private setRoutes = (): void => {
|
private setRoutes = (): void => {
|
||||||
this.app.use(cors())
|
this.app.use(
|
||||||
|
cors({
|
||||||
|
origin: "http://localhost:*",
|
||||||
|
credentials: true
|
||||||
|
})
|
||||||
|
)
|
||||||
this.app.use(
|
this.app.use(
|
||||||
fileUpload({
|
fileUpload({
|
||||||
limits: { fileSize: 10 * 1024 * 1024 }
|
limits: { fileSize: 10 * 1024 * 1024 }
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
this.app.post("/siafile", this.getSiaFile)
|
this.app.post("/siafile", this.postSiaFile)
|
||||||
|
this.app.get("/siafile/download", this.downloadSiaFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getSiaFile(
|
private async downloadSiaFile(req, res) {}
|
||||||
|
|
||||||
|
private async postSiaFile(
|
||||||
req: express.Request & any,
|
req: express.Request & any,
|
||||||
res: express.Response
|
res: express.Response
|
||||||
): Promise<express.Response> {
|
): Promise<express.Response> {
|
||||||
|
@ -69,19 +77,33 @@ export class Server {
|
||||||
try {
|
try {
|
||||||
const file: any = selectFile(req)
|
const file: any = selectFile(req)
|
||||||
|
|
||||||
const { data: stream } = await siad.post("/renter/stream", file.data, {
|
const selectContentLength = R.path(["headers", "Content-Length"])
|
||||||
headers: {
|
const cl = selectContentLength(req)
|
||||||
"Content-Type": "multipart/form-data"
|
console.log("cl is", cl)
|
||||||
},
|
|
||||||
responseType: "stream"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.attachment(file.name)
|
console.log("file is", file)
|
||||||
res.set("Content-Type", "application/octet-stream")
|
|
||||||
|
|
||||||
|
const { data: stream, headers } = await siad.post(
|
||||||
|
"/renter/stream",
|
||||||
|
file.data,
|
||||||
|
{
|
||||||
|
responseType: "stream"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const contentLength = headers["Content-Length"]
|
||||||
|
|
||||||
|
const pName = R.prop("name")
|
||||||
|
const splitFilename = R.compose(R.head, R.split(".sia"))
|
||||||
|
const fileName = R.compose(splitFilename, pName)(file)
|
||||||
|
|
||||||
|
res.set(
|
||||||
|
"Content-Disposition",
|
||||||
|
`attachment; filename="${fileName}"; filename*="${fileName}"`
|
||||||
|
)
|
||||||
|
res.set("Content-Length", contentLength)
|
||||||
stream.pipe(res)
|
stream.pipe(res)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("e is", e)
|
console.log("postSiaFile err:", e)
|
||||||
return res.json({ error: e.message })
|
return res.json({ error: e.message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
yarn.lock
33
yarn.lock
|
@ -3880,6 +3880,11 @@ depd@~1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||||
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||||
|
|
||||||
|
depd@~2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||||
|
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||||
|
|
||||||
deprecation@^2.0.0:
|
deprecation@^2.0.0:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
|
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
|
||||||
|
@ -4270,6 +4275,20 @@ express-fileupload@1.1.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
busboy "^0.3.1"
|
busboy "^0.3.1"
|
||||||
|
|
||||||
|
express-session@1.17.0:
|
||||||
|
version "1.17.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.0.tgz#9b50dbb5e8a03c3537368138f072736150b7f9b3"
|
||||||
|
integrity sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==
|
||||||
|
dependencies:
|
||||||
|
cookie "0.4.0"
|
||||||
|
cookie-signature "1.0.6"
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "~2.0.0"
|
||||||
|
on-headers "~1.0.2"
|
||||||
|
parseurl "~1.3.3"
|
||||||
|
safe-buffer "5.2.0"
|
||||||
|
uid-safe "~2.1.5"
|
||||||
|
|
||||||
express@^4.14.0:
|
express@^4.14.0:
|
||||||
version "4.17.1"
|
version "4.17.1"
|
||||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
|
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
|
||||||
|
@ -7897,6 +7916,11 @@ ramda@0.26.1, ramda@^0.26.1:
|
||||||
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
|
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
|
||||||
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
|
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
|
||||||
|
|
||||||
|
random-bytes@~1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
|
||||||
|
integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=
|
||||||
|
|
||||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
|
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||||
|
@ -8366,7 +8390,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
|
|
||||||
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
safe-buffer@5.2.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||||
|
@ -9295,6 +9319,13 @@ uid-number@0.0.6:
|
||||||
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
|
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
|
||||||
integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
|
integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
|
||||||
|
|
||||||
|
uid-safe@~2.1.5:
|
||||||
|
version "2.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a"
|
||||||
|
integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==
|
||||||
|
dependencies:
|
||||||
|
random-bytes "~1.0.0"
|
||||||
|
|
||||||
umask@^1.1.0:
|
umask@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
|
resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
|
||||||
|
|
Reference in New Issue