diff --git a/backend/src/prisma/prisma.service.ts b/backend/src/prisma/prisma.service.ts index 215fa4e..6f1fd60 100644 --- a/backend/src/prisma/prisma.service.ts +++ b/backend/src/prisma/prisma.service.ts @@ -1,5 +1,4 @@ import { Injectable } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; import { PrismaClient } from "@prisma/client"; @Injectable() @@ -8,7 +7,7 @@ export class PrismaService extends PrismaClient { super({ datasources: { db: { - url: "file:../data/pingvin-share.db", + url: "file:../data/pingvin-share.db?connection_limit=1", }, }, }); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1fb99c6..f2164b0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,6 +26,7 @@ "next-cookies": "^2.0.3", "next-http-proxy-middleware": "^1.2.5", "next-pwa": "^5.6.0", + "p-limit": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.7.1", @@ -6161,6 +6162,35 @@ } }, "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", @@ -6175,14 +6205,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/p-locate/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { "node": ">=10" }, @@ -8049,12 +8076,11 @@ } }, "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -12482,12 +12508,11 @@ } }, "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "requires": { - "yocto-queue": "^0.1.0" + "yocto-queue": "^1.0.0" } }, "p-locate": { @@ -12497,6 +12522,23 @@ "dev": true, "requires": { "p-limit": "^3.0.2" + }, + "dependencies": { + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } } }, "p-map": { @@ -13865,10 +13907,9 @@ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==" }, "yup": { "version": "0.32.11", diff --git a/frontend/package.json b/frontend/package.json index d5259f4..d127b32 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "next-cookies": "^2.0.3", "next-http-proxy-middleware": "^1.2.5", "next-pwa": "^5.6.0", + "p-limit": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.7.1", diff --git a/frontend/src/pages/upload.tsx b/frontend/src/pages/upload.tsx index 390b07d..ee59699 100644 --- a/frontend/src/pages/upload.tsx +++ b/frontend/src/pages/upload.tsx @@ -2,6 +2,7 @@ import { Button, Group } from "@mantine/core"; import { useModals } from "@mantine/modals"; import axios from "axios"; import { useRouter } from "next/router"; +import pLimit from "p-limit"; import { useEffect, useState } from "react"; import Meta from "../components/Meta"; import Dropzone from "../components/upload/Dropzone"; @@ -12,10 +13,11 @@ import useConfig from "../hooks/config.hook"; import useUser from "../hooks/user.hook"; import shareService from "../services/share.service"; import { FileUpload } from "../types/File.type"; -import { ShareSecurity } from "../types/share.type"; +import { Share, ShareSecurity } from "../types/share.type"; import toast from "../utils/toast.util"; -let share: any; +let share: Share; +const promiseLimit = pLimit(3); const Upload = () => { const router = useRouter(); @@ -41,7 +43,8 @@ const Upload = () => { }) ); share = await shareService.create(id, expiration, recipients, security); - for (let i = 0; i < files.length; i++) { + const uploadPromises = files.map((file, i) => { + // Callback to indicate current upload progress const progressCallBack = (progress: number) => { setFiles((files) => { return files.map((file, callbackIndex) => { @@ -54,11 +57,15 @@ const Upload = () => { }; try { - await shareService.uploadFile(share.id, files[i], progressCallBack); + return promiseLimit(() => + shareService.uploadFile(share.id, file, progressCallBack) + ); } catch { - files[i].uploadingProgress = -1; + file.uploadingProgress = -1; } - } + }); + + await Promise.all(uploadPromises); } catch (e) { if (axios.isAxiosError(e)) { toast.error(e.response?.data?.message ?? "An unkown error occured.");