aboutsummaryrefslogtreecommitdiffstats
path: root/src/server/Cache.hx
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/Cache.hx')
-rw-r--r--src/server/Cache.hx108
1 files changed, 88 insertions, 20 deletions
diff --git a/src/server/Cache.hx b/src/server/Cache.hx
index d772648..cfd5d88 100644
--- a/src/server/Cache.hx
+++ b/src/server/Cache.hx
@@ -2,6 +2,7 @@ package server;
import haxe.io.Path;
import js.lib.Promise;
+import js.node.Buffer;
import js.node.ChildProcess;
import js.node.Fs.Fs;
import js.node.stream.Readable;
@@ -9,16 +10,16 @@ import sys.FileSystem;
import utils.YoutubeUtils;
class Cache {
- final main:Main;
- final cacheDir:String;
-
- public final cachedFiles:Array<String> = [];
+ public final notEnoughSpaceErrorText = "Error: Not enough free space on server or file size is out of cache storage limit.";
public final isYtReady = false;
/** In bytes **/
public var storageLimit(default, null) = 3 * 1024 * 1024 * 1024;
+ final main:Main;
+ final cacheDir:String;
+ final cachedFiles:Array<String> = [];
final freeSpaceBlock = 10 * 1024 * 1024; // 10MB
public function new(main:Main, cacheDir:String) {
@@ -51,6 +52,24 @@ class Cache {
}
}
+ public function getCachedFiles():Array<String> {
+ return cachedFiles;
+ }
+
+ public function setCachedFiles(names:Array<String>) {
+ cachedFiles.resize(0);
+ for (name in names) cachedFiles.push(name);
+
+ final names = FileSystem.readDirectory(cacheDir);
+ for (name in names) {
+ if (name.startsWith(".")) continue;
+ if (FileSystem.isDirectory('$cacheDir/$name')) continue;
+ if (cachedFiles.contains(name)) continue;
+ trace('Remove non-tracked cache $name');
+ remove(name);
+ }
+ }
+
function log(client:Client, msg:String):Void {
main.serverMessage(client, msg);
trace(msg);
@@ -77,6 +96,15 @@ class Cache {
remove(inVideoName);
remove(inAudioName);
}
+ inline function cancelProgress():Void {
+ main.send(client, {
+ type: Progress,
+ progress: {
+ type: Canceled,
+ ratio: 1
+ }
+ });
+ }
if (isFileExists(inVideoName)) {
log(client, 'Caching $outName already in progress');
return;
@@ -117,6 +145,7 @@ class Cache {
dlVideo.on("error", err -> {
log(client, "Error during video download: " + err);
removeInputFiles();
+ cancelProgress();
});
final dlAudio:Readable<Dynamic> = ytdl(url, {
@@ -126,6 +155,7 @@ class Cache {
dlAudio.on("error", err -> {
log(client, "Error during audio download: " + err);
removeInputFiles();
+ cancelProgress();
});
var count = 0;
@@ -134,26 +164,40 @@ class Cache {
trace('$type track downloaded ($count/2)');
if (count < 2) return;
if (!isFileExists(inVideoName) || !isFileExists(inAudioName)) {
+ log(client, "Input files not found for making final video");
removeInputFiles();
+ cancelProgress();
return;
}
var size = FileSystem.stat('$cacheDir/$inVideoName').size;
size += FileSystem.stat('$cacheDir/$inAudioName').size;
// clean some space for full mp4
- removeOlderCache(size + freeSpaceBlock);
+ final hasSpace = removeOlderCache(size + freeSpaceBlock);
+ if (!hasSpace) {
+ removeInputFiles();
+ cancelProgress();
+ log(client, notEnoughSpaceErrorText);
+ return;
+ }
final args = '-y -i ./$inVideoName -i ./$inAudioName -c copy -map 0:v -map 1:a ./$outName'.split(" ");
final process = ChildProcess.spawn("ffmpeg", args, {
cwd: cacheDir,
- stdio: "ignore"
+ // stdio: "ignore"
});
- // process.stderr.on('data', (data) -> {
- // trace('FFmpeg stderr: ${data}');
- // });
+ final outputData:Array<Buffer> = [];
+ process.stderr.on("data", (data) -> outputData.push(data));
process.on("close", (code:Int) -> {
removeInputFiles();
if (code != 0) {
- log(client, 'Error: ffmpeg closed with code $code');
+ cancelProgress();
+ final errCodeMsg = 'Error: ffmpeg closed with code $code';
+ final admins = main.clients.filter(client -> client.isAdmin);
+ for (client in admins) {
+ log(client, Buffer.concat(outputData).toString());
+ log(client, errCodeMsg);
+ }
+ if (!admins.contains(client)) log(client, errCodeMsg);
return;
}
add(outName);
@@ -163,18 +207,28 @@ class Cache {
}
dlVideo.on("finish", () -> onComplete("Video"));
dlAudio.on("finish", () -> onComplete("Audio"));
+ inline function checkEnoughSpace(contentLength:Int):Void {
+ final hasSpace = removeOlderCache(contentLength + freeSpaceBlock);
+ if (!hasSpace) {
+ dlVideo.destroy();
+ dlAudio.destroy();
+ removeInputFiles();
+ cancelProgress();
+ main.serverMessage(client, notEnoughSpaceErrorText);
+ }
+ }
var isAudioStart = true;
dlAudio.on("progress", (chunkLength:Int, downloaded:Int, contentLength:Int) -> {
if (isAudioStart) {
isAudioStart = false;
- removeOlderCache(contentLength);
+ checkEnoughSpace(contentLength);
}
});
var isVideoStart = true;
dlVideo.on("progress", (chunkLength:Int, downloaded:Int, contentLength:Int) -> {
if (isVideoStart) {
isVideoStart = false;
- removeOlderCache(contentLength);
+ checkEnoughSpace(contentLength);
}
final ratio = (downloaded / contentLength).clamp(0, 1);
main.send(client, {
@@ -187,6 +241,7 @@ class Cache {
});
}).catchError(err -> {
removeInputFiles();
+ cancelProgress();
log(client, "" + err);
});
}
@@ -194,13 +249,8 @@ class Cache {
public function setStorageLimit(bytes:Int) {
storageLimit = cast bytes;
storageLimit = storageLimit.limitMin(0);
- final statfs = (Fs : Dynamic).statfs ?? return;
- statfs("/", (err, stats) -> {
- if (err != null) {
- trace(err);
- return;
- }
- final availSpace = (stats.bsize * stats.bavail - freeSpaceBlock).limitMin(0);
+ getFreeDiskSpace(availSpace -> {
+ final availSpace = (availSpace - freeSpaceBlock).limitMin(0);
removeOlderCache();
final freeSpace = getFreeSpace();
if (availSpace < freeSpace) {
@@ -212,6 +262,22 @@ class Cache {
});
}
+ public function getFreeDiskSpace(callback:(availSpace:Int) -> Void):Void {
+ final statfs = (Fs : Dynamic).statfs ?? {
+ trace("Warning: no fs.statfs support in current nodejs version (needs v18+)");
+ callback(storageLimit);
+ return;
+ }
+ statfs("/", (err, stats) -> {
+ if (err != null) {
+ trace(err);
+ callback(storageLimit);
+ return;
+ }
+ callback(stats.bsize * stats.bavail);
+ });
+ }
+
public function add(name:String) {
if (!cachedFiles.contains(name)) {
cachedFiles.unshift(name);
@@ -223,13 +289,15 @@ class Cache {
removeFile(name);
}
- public function removeOlderCache(addFileSize = 0):Void {
+ /** Returns `true` if there is enough space to save `addFileSize` bytes. **/
+ public function removeOlderCache(addFileSize = 0):Bool {
var space = getUsedSpace(addFileSize);
while (space > storageLimit) {
final name = cachedFiles.pop() ?? break;
removeFile(name);
space = getUsedSpace(addFileSize);
}
+ return space < storageLimit;
}
function removeFile(name:String):Void {
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage