hw4: ready for submission

This commit is contained in:
Claudio Maggioni 2019-10-13 13:29:03 +02:00
parent 0cb7ed641a
commit f6d54b18fd
2 changed files with 72 additions and 9 deletions

View File

@ -0,0 +1,4 @@
# Bonuses implemented:
- *Excercise 5*, File statistics
- *Excercise 6*, Tag cloud
- *Excercise 7*, JSON Tag cloud

View File

@ -8,6 +8,16 @@ const formidable = require('formidable');
const routes = Object.create(null);
function noSubPaths(req, path) {
const p = url.parse(req.url);
if (p.pathname != path && p.pathname != path) {
error(res, 404, `Only "${path}" path is accessible under this prefix`);
return true;
} else {
return false;
}
}
function error(res, code, text = '') {
res.writeHead(code, { 'Content-Type': 'text/html' });
res.end(`<!DOCTYPE html>
@ -28,7 +38,7 @@ function error(res, code, text = '') {
function fileData(reqUrl, prefix, options = {}) {
const uri = decodeURIComponent(
!options.isPath ? url.parse(reqUrl).pathname.substring(prefix.length) : reqUrl
).replace(/\/+$/, '');
).replace(/\/+$/, '');
const file = __dirname + '/NodeStaticFiles' + uri;
const name = file.substring(file.lastIndexOf('/') + 1);
const ext = !options.noExt ? name.substring(name.indexOf('.') + 1) : null;
@ -69,7 +79,7 @@ routes['explore'] = (req, res) => {
name: e.name,
dir: !e.isFile(),
path: (e.isFile() ? '/file' : '/explore') + uri +
(uri == '/' ? '' : '/') + e.name
(uri == '/' ? '' : '/') + e.name
});
}
@ -191,12 +201,8 @@ function wordMap(string) {
return wordDict;
}
routes['stats'] = (req, res) => {
function getFileStats(req, res, path, callback) {
const p = url.parse(req.url, true);
if (p.pathname != '/stats' && p.pathname != '/stats') {
error(res, 404, 'Only "/stats" path is accessible under this prefix');
return;
}
const reqFile = p && p.query && '/' + p.query['file'];
if (!reqFile) {
@ -204,9 +210,9 @@ routes['stats'] = (req, res) => {
return;
}
const { file, name, ext } = fileData(reqFile, '/stats', { isPath: true });
const { file, name, ext } = fileData(reqFile, path, { isPath: true });
if (ext != 'txt' && ext != 'html') {
error(res, 400, 'Only txt and html files can be processed by /stats');
error(res, 400, `Only txt and html files can be processed by ${path}`);
return;
}
@ -217,6 +223,18 @@ routes['stats'] = (req, res) => {
}
const dict = wordMap(data);
callback({ reqFile: reqFile, dict: dict });
});
}
routes['stats'] = (req, res) => {
if (noSubPaths(req, '/stats')) {
return;
}
getFileStats(req, res, '/stats', ({ reqFile, dict }) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(`<!DOCTYPE html>
<html lang="en">
@ -251,6 +269,47 @@ routes['stats'] = (req, res) => {
});
};
routes['cloud'] = (req, res) => {
if (noSubPaths(req, '/cloud')) {
return;
}
getFileStats(req, res, '/cloud', ({ reqFile, dict }) => {
if (req.headers.accept && req.headers.accept == 'application/json') {
res.writeHead(200, {'Content-Type': 'application/json' });
res.end(JSON.stringify(dict, null, 2));
} else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Cloud for ${reqFile}</title>
<style>
table { border-collapse: collapse; }
td, th { border: 1px solid black; }
th { font-weight: bold; }
</style>
</head>
<body>
<h1>Tag cloud for "${reqFile}"</h1>
<div class="cloud">`);
const max = Math.max(...Object.values(dict));
const min = Math.min(...Object.values(dict));
for (const word in dict) {
const size = 0.75 + ((dict[word] - min) / max) * 4 + 'rem';
res.write(`<span style="font-size: ${size}"> ${word} </span>`);
}
res.end(`</div>
</body>
</html>`);
}
});
};
// Main server handler
function onRequest(req, res) {
const pathname = url.parse(req.url).pathname;