From e0c3feaf86fe8fcc7f60ede8fed6bc8456cd728e Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sun, 7 Oct 2018 11:30:57 +0200 Subject: [PATCH] Added File Watcher Cached files will now be watched for changes. Also the preprocessor and chaching will now log. --- README.md | 4 +++- glob/style.sass | 6 ++++++ lib/caching.js | 33 ++++++++++++++++++++++++++++----- lib/preprocessor.js | 18 +++++++++++++++++- server.js | 1 + 5 files changed, 55 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b70f60f..1fe49b1 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,14 @@ This web server uses folders for every type of file (depending on the file's end } ] } + +You can embed sass files as link elements in html-pages. The sass files will be preprocessed to css before send to clients. The result will also be cached and the sass file will be watched for changes. If changes occur, the file will be preprocessed anew on the next request to the file. If not, the cached file will be send. HTML-files will also be cached because they are also manipulated by the preprocessor. All cached files are watched for changes. I.e. if changes to the file are detected the caching function isCached returns false. ``` Roadmap ---- **Done** - +- SASS-Files and caching of preprocessed files **ToDo** - Mounting of folders or files on other locations (by using the config.json) - a package.json because it seems to be important nowadays diff --git a/glob/style.sass b/glob/style.sass index 48452a7..920a5c1 100644 --- a/glob/style.sass +++ b/glob/style.sass @@ -23,6 +23,12 @@ body a color: $link-color +a:hover + color: lighten($link-color, 10%) + +a:visited + color: darken($link-color, 10%) + h1, h2, h3, h4, h5 line-height: 1.5em // tag-like classes diff --git a/lib/caching.js b/lib/caching.js index 31e5d93..b1466ca 100644 --- a/lib/caching.js +++ b/lib/caching.js @@ -23,6 +23,7 @@ exports.getCached = function(filename) { cf.last_call = Date.now(); // set the last call to now cf.call_count += 1; // increase the call count if (cf.data != null) return cf.data; + logger.debug("Returning cached data for %s : %s", filename, cf.path); return fs.readFileSync(cf.path); // return either the data or read the file }; @@ -32,21 +33,38 @@ exports.getCached = function(filename) { * @param {String} data The data form the file */ exports.cache = function(filename, data) { + logger.verbose("Creating cache entry for %s", filename); if (!fs.existsSync("./.cache")) fs.mkdirSync("./.cache"); // if the cache folder doesn't exist, create it let cache_fn = filename.replace(/[^\w\.]/g, "__"); // remove invalid path characters let count = 0; while (fs.existsSync(filename + count + ".cache")) count++; // check if a file with the same name already exists and increase count let cache_path = path.join(cache_dir, cache_fn+count+".cache"); // create the final file path. Cachedir + cached filename (without invalid) + count + .cache + logger.debug("Creating file %s", cache_path); fs.writeFile(cache_path, data, (error) => { + logger.debug("Created file cache entry for %s", filename); cache[filename] = { // create a cache-entry with the file's path when the file is written (so it won't be accessed before) "path": cache_path, // the last call to the file, the count of calls and an "last_call": null, // empty data field to store the file's data if the file "call_count": 0, // was called often "data": null, - "creation_time": Date.now() + "creation_time": Date.now(), + "changed": false }; + fs.watch(filename, (eventType) => { // watch the file for changes + logger.debug("Change detected on %s", filename); + if (eventType == 'change') cache[filename].changed = true; // if the event change is detected set the change attribute to true + }); }); // write the data asynchronously to the file }; +var logger = require("winston"); + +/** + * Sets the logger for logging + * @param {Winston Logger} newLogger + */ +exports.setLogger = function(newLogger) { + logger = newLogger; +} /** * Returns if the file is already cached @@ -59,18 +77,23 @@ exports.cache = function(filename, data) { */ exports.isCached = function(filename) { let cached_entry = cache[filename]; - if (cached_entry) { - if (cached_entry.path) { - return fs.existsSync(cached_entry.path); + if (cached_entry) { // check if the cache entry exists + logger.debug("Found cache entry for %s", filename); + if (cached_entry.changed) return false; // if a change was detected recache the file + if (cached_entry.path) { // check if the path variable is set + logger.debug("Found path entry for %s", filename) + return fs.existsSync(cached_entry.path); // return if the file exists } } - return false; + logger.debug("Found no cache entry for %s", filename); + return false; // return false if the cache entry doesn't exist } /** * A function that dumps the config into the config file after appending the cache to it. */ exports.cleanup = function() { + logger.verbose("Dumping cache into cache_dump file"); cache_dump["last"] = cache; fs.writeFileSync(config_path, JSON.stringify(cache_dump)); } diff --git a/lib/preprocessor.js b/lib/preprocessor.js index bbd892e..2cdc8dd 100644 --- a/lib/preprocessor.js +++ b/lib/preprocessor.js @@ -11,6 +11,16 @@ const fs = require("fs"), ".html": "html", ".htm": "hmtl" }; +var logger = require("winston"); + +/** + * Sets the logger for logging + * @param {Winston Logger} newLogger + */ +exports.setLogger = function(newLogger) { + logger = newLogger; + caching.setLogger(logger); +} /** * Returns the data for the file. In some cases the data is processed or loaded from cache. @@ -19,25 +29,31 @@ const fs = require("fs"), */ exports.getProcessed = function(filename) { try { + logger.debug("Processing File %s", filename); var extension = utils.getExtension(filename); var data = null; if (caching.isCached(filename)) return caching.getCached(filename) + logger.debug("File is not cached. Processing..."); switch (pp_config[extension]) { case "sass": + logger.debug("Processing sass %s", filename); data = Buffer.from(pp_sass.renderSync({ file: filename }).css).toString("utf-8"); break; case "html": + logger.debug("Processing html %s", filename); data = pp_html.formatHtml(filename); break; default: + logger.debug("No processor found for %s. Returning data.", filename); return fs.readFileSync(filename); } caching.cache(filename, data); + logger.debug("Cached file %s", filename); return data; } catch (error) { - console.error(error); + logger.error(error); return "Processing Error"; } } diff --git a/server.js b/server.js index 137c982..655dafb 100644 --- a/server.js +++ b/server.js @@ -85,6 +85,7 @@ const https = require('https'), */ function main() { try { + prepro.setLogger(logger); https.createServer(options, function(req, res) { logger.verbose({'msg': 'Received request', 'method': req.method, 'url': req.url});