form upload

This commit is contained in:
Eddie Wang 2019-12-05 17:49:29 -05:00
parent c5c7c7f809
commit f9d3d8b7f3
No known key found for this signature in database
GPG Key ID: DBFB3E83121BEDD1
4 changed files with 111 additions and 78 deletions

View File

@ -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>
) )

View File

@ -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"
} }
} }

View File

@ -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 })
} }
} }

View File

@ -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"