Skip to content

Commit

Permalink
Available disk space is now checked on startup
Browse files Browse the repository at this point in the history
Uploading when the server is cleaning up now just delays processing the request until it's ready, rather than sending a 503.
  • Loading branch information
hedgehog125 committed Jul 19, 2022
1 parent b58fe72 commit 2e33ef5
Show file tree
Hide file tree
Showing 27 changed files with 60 additions and 26 deletions.
12 changes: 12 additions & 0 deletions credits.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
=== Code ===
== Packages and tools ==
busboy (https://www.npmjs.com/package/busboy)
check-disk-space (https://www.npmjs.com/package/check-disk-space)
express: (https://www.npmjs.com/package/express)
ip: (https://www.npmjs.com/package/ip)
mime-types: (https://www.npmjs.com/package/mime-types)
node-gzip: (https://www.npmjs.com/package/node-gzip)
stream-meter: (https://www.npmjs.com/package/stream-meter)
Sveltekit (https://kit.svelte.dev/)

=== Images ===
== Key ==
Material Icons:
https://materialdesignicons.com/
Expand Down
9 changes: 6 additions & 3 deletions server/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"downloadedFile": 10
},
"clientRelated": {
"cleaningUp": 0.5,
"maxRoomsReached": 10,
"fileNotReady": 1,
"tooManyFiles": 5
Expand All @@ -31,9 +30,13 @@
},

"log": {
"unusual": true
"uploadErrors": true,
"diskSpaceLessThanLimit": true
},
"require": {
"diskSpaceMoreThanLimit": false
},
"serve": {
"gzip": false
"gzip": true
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified server/gzipBuild/app/immutable/manifest.json.gz
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed server/gzipBuild/app/immutable/start-ec45075e.js.gz
Binary file not shown.
Binary file modified server/gzipBuild/app/version.json.gz
Binary file not shown.
Binary file modified server/gzipBuild/index.html.gz
Binary file not shown.
Binary file modified server/gzipBuild/room.html.gz
Binary file not shown.
54 changes: 36 additions & 18 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
/*
TODO
Use await for when a request can't be completed due to the server cleaning up. It won't be long
Use a preflight system for the upload. Client sends request to a different URL, with the size of the file. Server sends back a random key and id it'll be at. This id and the space for the file is now reserved, client has 5 seconds to start the main request or everything's ondone and the code is invalid. The upload also fails if the file becomes bigger than what was stated upfront.
Check scaling
Preload images
More security stuff involving timings I guess? Mainly around async stuff and assuming data is still correct. Maybe delay processing new rooms when the folder is being created for a new room or something
Proper tab order
Check the max space in config is available
Use maps instead of objects generally. Objects should ideally be used in the same way as in strongly typed languages
= Bugs =
Probably not my fault:
State can desync with files, causing errors
Error: write EPIPE on download disconnect
Client aborting uploads isn't properly handled. The code will be 400 and request.aborted will be true "Error: Request aborted". Or at least sometimes...? Might be a busboy issue
*/


const GB_TO_BYTES = Math.pow(1024, 3);
const BYTES_TO_GB = 1 / GB_TO_BYTES;

const fs = require("fs/promises");
const oldFS = require("fs");
Expand All @@ -28,6 +26,7 @@ const busboy = require("busboy");
const mime = require("mime-types");
const meter = require("stream-meter");
const serveCompressed = require("express-precompressed");
const getDiskSpace = require("check-disk-space").default;

const ipPackage = require("ip");
const IP = ipPackage.address();
Expand All @@ -46,7 +45,10 @@ const state = {
totalSize: 0,
totalFileCount: 0,

cleaningUp: false
tasks: {
cleaningUp: null,
loadConfig: null
}
};
let config; // It'll be loaded from the disk
let PORT; // Loaded as part of config or from the environment variable
Expand Down Expand Up @@ -83,10 +85,29 @@ const loadConfig = async _ => {
PORT = process.env.PORT?? config.port;
};

const cleanUp = async _ => {
state.cleaningUp = true;
await helper.clearDir("sharedFiles", fs, path);
state.cleaningUp = false;
const checkDiskSpace = async _ => {
let info = await getDiskSpace(__dirname);
await state.tasks.loadConfig;

let maxSpace = config.limits.max.totalFileSize - state.totalSize;
let notEnoughSpace = maxSpace > info.free;

if (notEnoughSpace) {
const message = `
The amount of space left on this computer is less than the maximum total uploads can take up. You might want to reduce the maximum or free up some space.
${maxSpace * BYTES_TO_GB}GB is expected but there's only ${info.free * BYTES_TO_GB} available.
`;
if (config.require.diskSpaceMoreThanLimit) {
throw new Error(message);
}
else if (config.log.diskSpaceLessThanLimit) {
console.warn(message);
}
}
};

const cleanUp = _ => {
state.tasks.cleaningUp = helper.clearDir("sharedFiles", fs, path);
};

const startServer = _ => {
Expand Down Expand Up @@ -211,11 +232,7 @@ const startServer = _ => {
});

app.post("/room/upload/:roomName/", async (req, res) => {
if (state.cleaningUp) {
res.setHeader("Retry-After", config.timings.clientRelated.cleaningUp);
res.status(503).send("CleaningUp");
return;
}
await state.tasks.cleaningUp;

const max = config.limits.max;
if (state.totalFileCount == max.totalFileCount) {
Expand All @@ -227,8 +244,8 @@ const startServer = _ => {
const room = await getOrCreateRoom(req.params.roomName);
if (! checks.underRoomLimit(room, res)) return;

let spaceLeft = max.totalFileSize - state.totalSize;
let maxFilesize = max.fileSize == -1? spaceLeft : Math.min(max.fileSize, spaceLeft);
const spaceLeft = max.totalFileSize - state.totalSize;
const maxFilesize = max.fileSize == -1? spaceLeft : Math.min(max.fileSize, spaceLeft);

let fileSize = parseInt(req.headers["content-length"]); // Not completely accurate due to overhead but will be reduced once the length is known
if (fileSize - max.expectedUploadOverhead > maxFilesize) { // Stop the request early if it'll be too big
Expand Down Expand Up @@ -306,7 +323,7 @@ const startServer = _ => {
deleteUpload(room, id);
res.end();

if (config.log.unusual) {
if (config.log.uploadErrors) {
if (stream) {
console.log("File upload failed due to client disconnecting.");
}
Expand Down Expand Up @@ -449,7 +466,8 @@ const main = _ => {
};

const start = async _ => {
await loadConfig();
state.tasks.loadConfig = loadConfig();
await Promise.all([state.tasks.loadConfig, checkDiskSpace()]);

cleanUp();
startServer();
Expand Down
1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"license": "GPL-3.0",
"dependencies": {
"busboy": "^1.6.0",
"check-disk-space": "^3.3.1",
"express": "^4.18.1",
"express-precompressed": "^1.0.0",
"ip": "^1.1.8",
Expand Down
2 changes: 1 addition & 1 deletion static/build/app/immutable/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
".svelte-kit/runtime/client/start.js": {
"file": "start-844c4abc.js",
"file": "start-2b9897d8.js",
"src": ".svelte-kit/runtime/client/start.js",
"isEntry": true,
"imports": [
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion static/build/app/version.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"1658237858244"}
{"version":"1658242321512"}
2 changes: 1 addition & 1 deletion static/build/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html><html lang=en><meta charset=utf-8><link href=./favicon.png rel="alternate icon" type=image/png sizes=32x32><link href=./favicon.svg rel=icon type=image/svg+xml size=64x64><meta content=#1e3bbe name=theme-color><link href=manifest.json rel=manifest><link href=appIcon.png rel=apple-touch-icon type=image/png sizes=512x512><meta content="width=device-width,initial-scale=1" name=viewport><meta content="Easily and quickly share files over your LAN" name=description><title>LANFS</title><meta content="" http-equiv=content-security-policy><link href=/app/immutable/assets/pages/index.svelte-56891da8.css rel=stylesheet><link href=/app/immutable/assets/TopBar-58fadc1e.css rel=stylesheet><link href=/app/immutable/start-844c4abc.js rel=modulepreload><link href=/app/immutable/chunks/index-e18ba743.js rel=modulepreload><link href=/app/immutable/layout.svelte-ab90e838.js rel=modulepreload><link href=/app/immutable/pages/index.svelte-73518255.js rel=modulepreload><link href=/app/immutable/chunks/TopBar-b4235a47.js rel=modulepreload><div><main><main><div class="svelte-1kfyryn main"><h1 class=svelte-1kfyryn>LANFS</h1></div><div class="svelte-1kfyryn space"></div><br></main><main class=svelte-1v90lka><h1 class=svelte-1v90lka>Welcome!</h1></main><main class=svelte-1rf9297><div class=svelte-1rf9297><h2 class=svelte-1rf9297>To get started, enter a new or existing room name...</h2><form class=svelte-1rf9297><input aria-label="A name for a new or existing room" class=svelte-1rf9297 placeholder="Enter a room name..."><br class=svelte-t39mn0><button class=svelte-1rf9297 type=submit>Join</button></form></div></main></main><script data-sveltekit-hydrate=1jnfd7z type=module>import { start } from "/app/immutable/start-844c4abc.js";
<!DOCTYPE html><html lang=en><meta charset=utf-8><link href=./favicon.png rel="alternate icon" type=image/png sizes=32x32><link href=./favicon.svg rel=icon type=image/svg+xml size=64x64><meta content=#1e3bbe name=theme-color><link href=manifest.json rel=manifest><link href=appIcon.png rel=apple-touch-icon type=image/png sizes=512x512><meta content="width=device-width,initial-scale=1" name=viewport><meta content="Easily and quickly share files over your LAN" name=description><title>LANFS</title><meta content="" http-equiv=content-security-policy><link href=/app/immutable/assets/pages/index.svelte-56891da8.css rel=stylesheet><link href=/app/immutable/assets/TopBar-58fadc1e.css rel=stylesheet><link href=/app/immutable/start-2b9897d8.js rel=modulepreload><link href=/app/immutable/chunks/index-e18ba743.js rel=modulepreload><link href=/app/immutable/layout.svelte-ab90e838.js rel=modulepreload><link href=/app/immutable/pages/index.svelte-73518255.js rel=modulepreload><link href=/app/immutable/chunks/TopBar-b4235a47.js rel=modulepreload><div><main><main><div class="svelte-1kfyryn main"><h1 class=svelte-1kfyryn>LANFS</h1></div><div class="svelte-1kfyryn space"></div><br></main><main class=svelte-1v90lka><h1 class=svelte-1v90lka>Welcome!</h1></main><main class=svelte-1rf9297><div class=svelte-1rf9297><h2 class=svelte-1rf9297>To get started, enter a new or existing room name...</h2><form class=svelte-1rf9297><input aria-label="A name for a new or existing room" class=svelte-1rf9297 placeholder="Enter a room name..."><br class=svelte-t39mn0><button class=svelte-1rf9297 type=submit>Join</button></form></div></main></main><script data-sveltekit-hydrate=1jnfd7z type=module>import { start } from "/app/immutable/start-2b9897d8.js";
start({
target: document.querySelector('[data-sveltekit-hydrate="1jnfd7z"]').parentNode,
paths: {"base":"","assets":""},
Expand Down
2 changes: 1 addition & 1 deletion static/build/room.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html><html lang=en><meta charset=utf-8><link href=./favicon.png rel="alternate icon" type=image/png sizes=32x32><link href=./favicon.svg rel=icon type=image/svg+xml size=64x64><meta content=#1e3bbe name=theme-color><link href=manifest.json rel=manifest><link href=appIcon.png rel=apple-touch-icon type=image/png sizes=512x512><meta content="width=device-width,initial-scale=1" name=viewport><meta content="Easily and quickly share files over your LAN" name=description><title>LANFS</title><meta content="" http-equiv=content-security-policy><main><link href=/app/immutable/assets/download-ddd256eb.svg rel=preload as=image><link href=/app/immutable/assets/close-02f49dd1.svg rel=preload as=image><link href=/app/immutable/assets/timer-plus-0c3cdcef.svg rel=preload as=image><link href=/app/immutable/assets/file-document-outline-8da5362f.svg rel=preload as=image></main><link href=/app/immutable/assets/pages/room.svelte-a4d60193.css rel=stylesheet><link href=/app/immutable/assets/TopBar-58fadc1e.css rel=stylesheet><link href=/app/immutable/start-844c4abc.js rel=modulepreload><link href=/app/immutable/chunks/index-e18ba743.js rel=modulepreload><link href=/app/immutable/layout.svelte-ab90e838.js rel=modulepreload><link href=/app/immutable/pages/room.svelte-b5ceba1b.js rel=modulepreload><link href=/app/immutable/chunks/TopBar-b4235a47.js rel=modulepreload><div><main><main><div class="svelte-1kfyryn main"><a class=svelte-1kfyryn href=/ ><img alt=Back class=svelte-1kfyryn height=24 src=/app/immutable/assets/back-a78e1fd6.svg width=24></a><button class=svelte-1kfyryn><img alt="Upload a file" class=svelte-1kfyryn height=24 src=/app/immutable/assets/upload-96bb5f35.svg width=24></button> <input class=svelte-1kfyryn multiple type=file><h1 class=svelte-1kfyryn>LANFS</h1></div><div class="svelte-1kfyryn space"></div><br></main><main class=svelte-lj1lm6><div class=svelte-lj1lm6><p class=svelte-lj1lm6>Connecting...</div></main></main><script data-sveltekit-hydrate=15llurs type=module>import { start } from "/app/immutable/start-844c4abc.js";
<!DOCTYPE html><html lang=en><meta charset=utf-8><link href=./favicon.png rel="alternate icon" type=image/png sizes=32x32><link href=./favicon.svg rel=icon type=image/svg+xml size=64x64><meta content=#1e3bbe name=theme-color><link href=manifest.json rel=manifest><link href=appIcon.png rel=apple-touch-icon type=image/png sizes=512x512><meta content="width=device-width,initial-scale=1" name=viewport><meta content="Easily and quickly share files over your LAN" name=description><title>LANFS</title><meta content="" http-equiv=content-security-policy><main><link href=/app/immutable/assets/download-ddd256eb.svg rel=preload as=image><link href=/app/immutable/assets/close-02f49dd1.svg rel=preload as=image><link href=/app/immutable/assets/timer-plus-0c3cdcef.svg rel=preload as=image><link href=/app/immutable/assets/file-document-outline-8da5362f.svg rel=preload as=image></main><link href=/app/immutable/assets/pages/room.svelte-a4d60193.css rel=stylesheet><link href=/app/immutable/assets/TopBar-58fadc1e.css rel=stylesheet><link href=/app/immutable/start-2b9897d8.js rel=modulepreload><link href=/app/immutable/chunks/index-e18ba743.js rel=modulepreload><link href=/app/immutable/layout.svelte-ab90e838.js rel=modulepreload><link href=/app/immutable/pages/room.svelte-b5ceba1b.js rel=modulepreload><link href=/app/immutable/chunks/TopBar-b4235a47.js rel=modulepreload><div><main><main><div class="svelte-1kfyryn main"><a class=svelte-1kfyryn href=/ ><img alt=Back class=svelte-1kfyryn height=24 src=/app/immutable/assets/back-a78e1fd6.svg width=24></a><button class=svelte-1kfyryn><img alt="Upload a file" class=svelte-1kfyryn height=24 src=/app/immutable/assets/upload-96bb5f35.svg width=24></button> <input class=svelte-1kfyryn multiple type=file><h1 class=svelte-1kfyryn>LANFS</h1></div><div class="svelte-1kfyryn space"></div><br></main><main class=svelte-lj1lm6><div class=svelte-lj1lm6><p class=svelte-lj1lm6>Connecting...</div></main></main><script data-sveltekit-hydrate=15llurs type=module>import { start } from "/app/immutable/start-2b9897d8.js";
start({
target: document.querySelector('[data-sveltekit-hydrate="15llurs"]').parentNode,
paths: {"base":"","assets":""},
Expand Down

0 comments on commit 2e33ef5

Please sign in to comment.