little-library/server.js

158 lines
4.9 KiB
JavaScript

const path = require('path');
const fs = require('fs');
const express = require('express');
const http = require('http');
const socketio = require('socket.io');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
const filenamify = require('filenamify');
const unusedFilename = require('unused-filename');
const settings = require('./settings.json');
function Server () {
this.server = express();
this.http = http.Server(this.server);
this.io = socketio(this.http);
this.fileLocation = path.resolve(settings.fileLocation);
this.historyLocation = path.resolve(settings.historyLocation);
this.takenBooks = [];
this.server.use(helmet());
this.server.use(bodyParser.json()); // support json encoded bodies
this.server.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
this.server.use(fileUpload({ // support file uploads
abortOnLimit: true,
limits: {
fileSize: (settings.maxFileSize > 0 ? settings.maxFileSize * 1024 * 1024 : Infinity), // filesize in bytes (settings accepts MB)
},
}));
this.server.use(express.static(path.join(__dirname, './public/')));
this.server.get('/', (req, res) => {
const page = path.join(__dirname, './public/index.html');
res.sendFile(page);
});
this.server.post('/give', (req, res) => {
let success = false;
if (Object.keys(req.files).length > 0 && req.body.hasOwnProperty('title') && req.body.hasOwnProperty('summary')) {
const { book } = req.files;
const { title, author, summary } = req.body;
const fileType = book.name.substr(book.name.lastIndexOf('.'));
success = this.addBook({ book, title, author, summary, fileType });
}
res.send(success);
});
this.io.on('connection', socket => {
this.broadcastVisitors();
socket.on('take book', bookId => {
const fileLocation = this.takeBook(bookId, socket.id);
if (fileLocation) {
console.log(socket.id + ' removed ' + bookId);
const downloadLocation = fileLocation.substr(fileLocation.lastIndexOf('/'));
socket.emit('./files' + downloadLocation);
}
});
socket.on('disconnect', () => {
this.broadcastVisitors();
this.deleteBooks(socket.id);
});
});
}
Server.prototype.broadcastVisitors = function () {
const numberConnected = this.io.of('/').clients().connected.length;
this.io.emit('connected', numberConnected);
}
Server.prototype.start = function () {
this.http.listen(settings.port, () => {
console.log('Started server on port ' + settings.port);
});
}
Server.prototype.addBook = function (uploadData = {}) {
const { book } = uploadData;
const bookId = this.uuid4();
const bookPath = path.resolve(this.fileLocation, bookId);
const bookData = {
title: uploadData.title,
author: uploadData.author,
summary: uploadData.summary,
fileType: book.name.substr(book.name.lastIndexOf('.')),
}
let success = false;
book.mv(unusedFilename.sync(path.resolve(bookPath, bookData.fileType)), function (err) {
if (!err) {
fs.writeFileSync(unusedFilename.sync(path.resolve(bookPath, '.json')), JSON.stringify(bookData));
success = true;
} else {
success = err;
}
});
return success;
}
Server.prototype.takeBook = function (bookId, socketId) {
return this.checkId(bookId, (bookPath, bookDataPath, bookData) => {
const bookName = filenamify(bookData.title);
const newFileName = unusedFilename.sync(path.resolve(this.fileLocation, bookName, bookData.fileType));
bookData.fileName = newFileName;
fs.renameSync(bookPath, newFileName);
fs.writeFileSync(bookDataPath, JSON.stringify(bookData));
takenBooks.push({ socketId, bookId });
return newFileName;
});
}
Server.prototype.checkId = function (bookId, callback = () => {}) {
const bookDataPath = path.resolve(this.fileLocation, bookId, '.json');
if (fs.existsSync(bookDataPath)) {
const bookDataRaw = fs.readFileSync(bookDataPath);
if (bookDataRaw) {
const bookData = JSON.parse(bookDataRaw);
const bookPath = path.resolve(this.fileLocation, bookId, bookData.fileType);
if (fs.existsSync(bookPath)) {
return callback(bookPath, bookDataPath, bookData);
}
}
}
return false;
}
Server.prototype.deleteBooks = function (socketId) {
this.takenBooks.forEach(data => {
if (data.socketId === socketId) {
this.checkId(data.bookId, (bookPath, bookDataPath) => {
fs.unlinkSync(bookPath);
fs.renameSync(bookDataPath, path.resolve(this.historyLocation, data.bookId, '.json'));
});
}
});
this.takenBooks = this.takenBooks.filter(data => data.socketId === socketId);
}
Server.prototype.uuid4 = function () {
// https://stackoverflow.com/a/2117523
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}