Stremlined dependencies | built ad'Hoc http server
This commit is contained in:
86
server/src/core/HTTPServer.ts
Normal file
86
server/src/core/HTTPServer.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import http from 'http';
|
||||
import url from 'url';
|
||||
import fs, { open, close } from 'fs';
|
||||
import { parse, join } from 'path';
|
||||
|
||||
namespace server {
|
||||
export const mimes = {
|
||||
'.html': 'text/html',
|
||||
'.ico': 'image/x-icon',
|
||||
'.js': 'text/javascript',
|
||||
'.json': 'application/json',
|
||||
'.css': 'text/css',
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.webp': 'image/webp',
|
||||
};
|
||||
}
|
||||
|
||||
class Jean {
|
||||
private workingDir: string;
|
||||
|
||||
/**
|
||||
* Jean static file server its only purpose is serving SPA and images
|
||||
* with the lowest impact possible.
|
||||
* @param workingDir sets the root directory automatically trying index.html
|
||||
* If specified the file in addition to the directory it will serve the
|
||||
* file directly.
|
||||
* *e.g* new Jean(path.join(__dirname, 'dist')) will try
|
||||
* index.html from the dist directory;
|
||||
* @author me :D
|
||||
*/
|
||||
|
||||
constructor(workingDir: string) {
|
||||
this.workingDir = workingDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a static file server
|
||||
* @returns an instance of a standard NodeJS http.Server
|
||||
*/
|
||||
public createServer(): http.Server {
|
||||
return http.createServer((req, res) => {
|
||||
// parse the current given url
|
||||
const parsedUrl = url.parse(req.url, false)
|
||||
// extract the pathname and guard it with the working dir
|
||||
let pathname = join(this.workingDir, `.${parsedUrl.pathname}`);
|
||||
// extract the file extension
|
||||
const ext = parse(pathname).ext;
|
||||
|
||||
// open the file or directory and fetch its descriptor
|
||||
open(pathname, 'r', (err, fd) => {
|
||||
// whoops, not found, send a 404
|
||||
if (err) {
|
||||
res.statusCode = 404;
|
||||
res.end(`File ${pathname} not found!`);
|
||||
return;
|
||||
}
|
||||
// something's gone wrong it's not a file or a directory
|
||||
fs.fstat(fd, (err, stat) => {
|
||||
if (err) {
|
||||
res.statusCode = 500;
|
||||
res.end(err);
|
||||
}
|
||||
// try file index.html
|
||||
if (stat.isDirectory()) {
|
||||
pathname = join(pathname, 'index.html')
|
||||
}
|
||||
// read the file
|
||||
fs.readFile(pathname, (err, data) => {
|
||||
if (err) {
|
||||
res.statusCode = 500;
|
||||
res.end(`Error reading the file: ${err}`);
|
||||
} else {
|
||||
// infer it's extension otherwise it's the index.html
|
||||
res.setHeader('Content-type', server.mimes[ext] || 'text/html');
|
||||
res.end(data);
|
||||
close(fd);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Jean;
|
||||
@@ -2,6 +2,7 @@ import { spawn } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { Readable } from 'stream';
|
||||
import { deleteDownloadByPID, insertDownload } from '../db/db';
|
||||
import { ISettings } from '../interfaces/ISettings';
|
||||
import Logger from '../utils/BetterLogger';
|
||||
|
||||
const log = new Logger();
|
||||
@@ -9,15 +10,15 @@ const log = new Logger();
|
||||
/**
|
||||
* Represents a download process that spawns yt-dlp.
|
||||
* @constructor
|
||||
* @param {string} url - The downlaod url.
|
||||
* @param {Array<String>} params - The cli arguments passed by the frontend.
|
||||
* @param {*} settings - The download settings passed by the frontend.
|
||||
* @param url - The downlaod url.
|
||||
* @param params - The cli arguments passed by the frontend.
|
||||
* @param settings - The download settings passed by the frontend.
|
||||
*/
|
||||
|
||||
class Process {
|
||||
private url: string;
|
||||
private params: Array<string>;
|
||||
private settings: any;
|
||||
private settings: ISettings;
|
||||
private stdout: Readable;
|
||||
private pid: number;
|
||||
private info: any;
|
||||
@@ -35,11 +36,11 @@ class Process {
|
||||
|
||||
/**
|
||||
* function that launch the download process, sets the stdout property and the pid
|
||||
* @param {Function} callback not yet implemented
|
||||
* @returns {Promise<this>} the process instance
|
||||
* @param callback not yet implemented
|
||||
* @returns the process instance
|
||||
*/
|
||||
async start(callback?: Function): Promise<this> {
|
||||
await this.#__internalGetInfo();
|
||||
await this.internalGetInfo();
|
||||
|
||||
const ytldp = spawn(this.exePath,
|
||||
['-o', `${this.settings?.download_path || 'downloads/'}%(title)s.%(ext)s`]
|
||||
@@ -69,8 +70,8 @@ class Process {
|
||||
* function used internally by the download process to fetch information, usually thumbnail and title
|
||||
* @returns Promise to the lock
|
||||
*/
|
||||
async #__internalGetInfo() {
|
||||
let lock = true;
|
||||
private async internalGetInfo() {
|
||||
this.lock = true;
|
||||
let stdoutChunks = [];
|
||||
const ytdlpInfo = spawn(this.exePath, ['-s', '-j', this.url]);
|
||||
|
||||
@@ -93,7 +94,7 @@ class Process {
|
||||
}
|
||||
});
|
||||
|
||||
if (!lock) {
|
||||
if (!this.lock) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,15 @@ import { from, interval } from 'rxjs';
|
||||
import { throttle } from 'rxjs/operators';
|
||||
import { pruneDownloads } from '../db/db';
|
||||
import { killProcess } from '../utils/procUtils';
|
||||
import { Socket } from 'socket.io';
|
||||
import { IPayload } from '../interfaces/IPayload';
|
||||
import { ISettings } from '../interfaces/ISettings';
|
||||
import Logger from '../utils/BetterLogger';
|
||||
import Process from './Process';
|
||||
import ProcessPool from './ProcessPool';
|
||||
import { Socket } from 'socket.io';
|
||||
import { IPayload } from '../interfaces/IPayload';
|
||||
|
||||
// settings read from settings.json
|
||||
let settings;
|
||||
let settings: ISettings;
|
||||
let coldRestart = true;
|
||||
const log = new Logger();
|
||||
|
||||
@@ -20,7 +21,7 @@ try {
|
||||
settings = require('../settings.json');
|
||||
}
|
||||
catch (e) {
|
||||
console.warn("settings.json not found");
|
||||
log.warn('dl', 'settings.json not found');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +96,6 @@ export async function retriveDownload(socket: Socket) {
|
||||
if (coldRestart) {
|
||||
coldRestart = false;
|
||||
let downloads = await pruneDownloads();
|
||||
console.log(downloads)
|
||||
// sanitize
|
||||
downloads = [... new Set(downloads.filter(el => el !== undefined))];
|
||||
log.info('dl', `Cold restart, retrieving ${downloads.length} jobs`)
|
||||
|
||||
3
server/src/interfaces/ISettings.ts
Normal file
3
server/src/interfaces/ISettings.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface ISettings {
|
||||
download_path: string
|
||||
}
|
||||
@@ -1,19 +1,15 @@
|
||||
import Koa from 'koa';
|
||||
import serve from 'koa-static';
|
||||
import cors from '@koa/cors';
|
||||
import { logger, splash } from './utils/logger';
|
||||
import { join } from 'path';
|
||||
import { Server } from 'socket.io';
|
||||
import { createServer } from 'http';
|
||||
import { ytdlpUpdater } from './utils/updater';
|
||||
import { download, abortDownload, retriveDownload, abortAllDownloads } from './core/downloader';
|
||||
import Logger from './utils/BetterLogger';
|
||||
import { retrieveAll, init } from './db/db';
|
||||
import { getFreeDiskSpace } from './utils/procUtils';
|
||||
import Logger from './utils/BetterLogger';
|
||||
import Jean from './core/HTTPServer';
|
||||
|
||||
const app = new Koa()
|
||||
const log = new Logger()
|
||||
const server = createServer(app.callback())
|
||||
const server = new Jean(join(__dirname, 'frontend')).createServer();
|
||||
const log = new Logger();
|
||||
const io = new Server(server, {
|
||||
cors: {
|
||||
origin: "*",
|
||||
@@ -55,12 +51,9 @@ io.on('disconnect', (socket) => {
|
||||
logger('ws', `${socket.handshake.address} disconnected`)
|
||||
})
|
||||
|
||||
app
|
||||
.use(cors())
|
||||
.use(serve(join(__dirname, 'frontend')))
|
||||
|
||||
splash()
|
||||
log.info('koa', `Server started on port ${process.env.PORT || 3022}`)
|
||||
log.info('http', `Server started on port ${process.env.PORT || 3022}`)
|
||||
|
||||
init()
|
||||
.then(() => server.listen(process.env.PORT || 3022))
|
||||
|
||||
Reference in New Issue
Block a user