UNPKG

abstractmechanic

Version:

NodeJS Framework, small footprint, fast learning curve. This framework is perfect for produce apps fast

302 lines (243 loc) 9.97 kB
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<== ==> Program-Name: AbstractMechanics <== ==> Lang/Syntax: JavaScript (NodeJS Native Library) <== ==> Program-Type: Framework (for Node Env.) <== ==> Developer: Katana-Development/ A.J. Chamber <== ==> Created-On: [2020-JUN-15th] <== ==> Updated-On: [2020-JULY-1st] <== ==> ABOUT: <== ==> AbstractMechanics is a framework created for NodeJS, <==` ==> currently it is in development and small. I intend to use <== ==> it for my own custom project, however; if other developers <== ==> ever used it that would be really awesome. <== ==>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<== */ const formidable = require('formidable'); const http = require('http'); const url = require('url'); const path = require('path'); const fs = require('fs'); const events = require('events'); const {SSL_OP_SSLEAY_080_CLIENT_DH_BUG} = require('constants'); var ee = new events.EventEmitter(); //? ============( CLASS: 'Backend' )============ class Backend { /** @constructor * @memberof Backend * @param {string} __rootdir **/ constructor(__rootdir) { this.port = 1000; this.__rootdir = __rootdir; } /** @method Server() * @memberof Backend * @param {number} port **/ server(port) { this.port = port; http.createServer((req, res) => { const reqData = parseHttpRequest(req, res); var event = ''; var triggers = ''; //! =======================( GET REQUEST ROUTING )======================= if(req.method.toUpperCase() == 'GET') { printEzRead(`GET REQUEST RECIEVED`, reqData); event = 'EventUrl_' + reqData.pathname; triggers = ee.listenerCount(event); if(triggers > 0) { ee.emit(event, reqData.contenttype, res); } else { event = 'EventDir_' + reqData.dirname; triggers = ee.listenerCount(event); if(triggers > 0) { ee.emit(event, reqData, res); } else { console.log('\nHTTP-404: Not Found\n'); serveStatus(404, res) } } //! =======================( POST REQUEST ROUTING )======================= } else if(req.method.toUpperCase() == 'POST') { const form = formidable({multiples: true}); form.parse(req, (err, formData) => { if(err) throw err; event = `EventForm_${reqData.pathname}`; ee.emit(event, reqData, res, formData); }); } else { console.log('\nHTTP-406: Not Acceptable, likely to do with content type\n'); serveStatus(406, res) }; }).listen(this.port); printEzRead('Server Created Successfully', `Port Listening on #${port}`); }; /** @method Form() * @memberof Backend * @param {string} actionUrl "Forms action URL, proprty of HTML element FORM" * @callback callback "Async callback that allows logic to be dynamicly added to the 'Form Method' anywhere it is called, i found this to be perfect for a method that is a sort of form abstraction." Callback has 3 arguments, (reqData - contains HTTP Request Data), (res - Contains the HTTP Response Object for making a response to the requesting computer), (formData - parsed data from the form that the user submited. Parsed using formidable.)" * @example * <!-- action property --> * <form method='POST' action='/post/form/login.php'> **/ form(actionUrl, callback) { ee.on(`EventForm_${actionUrl}`, (reqData, res, formData) => { callback(reqData, res, formData); }); } /** @method URl() * @memberof Backend "Abstraction of the applications Serverside/backend" * @param {string} url "Select a valid URl" * @param {string} filepath "Filepath of the file to be served from selected URl" **/ url(url, filepath) { ee.on(`EventUrl_${url}`, (contenttype, res) => { filepath = path.join(this.__rootdir, filepath); if(fs.existsSync(filepath)) { fs.readFile(filepath, (err, data) => { res.writeHead(200, contenttype); res.write(data); res.end(); }); return 0; } else { console.log('\nHTTP-400: Bad Request\n'); serveStatus(400, res) return -1; } }); } /** @method Directory() * @memberof Backend * @param {string} url * @param {string} dir "Select a directory to publisize with the seleted url as the URL prefix to the filename" * @example * dir('/css', '/public/assets/css); * * 'http://localhost/css/stylesheet.css' === 'http://localhost/public/assets/css/stylesheet.css' **/ directory(url, dir) { ee.on(`EventDir_${url}`, (reqData, res) => { var filepath = path.join(this.__rootdir, dir, reqData.filename); if(fs.existsSync(filepath)) { fs.readFile(filepath, (err, data) => { res.writeHead(200, reqData.contenttype); res.write(data); res.end(); return 0; }); } else { console.log('\nHTTP-400: Bad Request\n'); serveStatus(400, res) return -1; } }); } } //? ============( STAND ALONE FUNCTIONS )============ /** @function printEzRead * @param {string} header Enter a string that will diplay as a title to the printed data **/ function printEzRead(header) { var values = Object.values(arguments); console.log(`\n\n\n\t\t===============|| ${header} ||===============`); values.forEach((value, i) => { if(i !== 0) {console.log(value);} }); } /** parseHttpRequest doesn't export. Should be no reason for anyone to use it anywhere but here. **/ function parseHttpRequest(req, res) { const reqUrl = req.url; const reqPathname = url.parse(reqUrl).pathname; const parsedHttpRequest = { url: reqUrl, method: req.method, pathname: reqPathname, filename: path.basename(reqPathname), dirname: path.dirname(reqPathname), ext: path.extname(reqPathname), contenttype: getContentType(path.extname(reqPathname), res), cookies: req.headers.cookie }; return parsedHttpRequest; } /** @function getContentType * @param {string} fileExt * @return {Content-Type} @typedef JSON "{"Content-Type" : "?/?"} returns the complete json object needed for most common file extention/mime types." **/ function getContentType(fileExt, res) { switch(fileExt) { case '': return new Object({"Content-Type": "text/html"}); case '.html': return new Object({"Content-Type": "text/html"}); case '.css': return new Object({"Content-Type": "text/css"}); case '.xml': return new Object({"Content-Type": "text/xml"}); case '.txt': return new Object({"Content-Type": "text/plain"}); case '.ico': return new Object({"Content-Type": "image/x-icon"}); case '.jpg': return new Object({"Content-Type": "image/jpeg"}); case '.png': return new Object({"Content-Type": "image/png"}); case '.gif': return new Object({"Content-Type": "image/gif"}); case '.js': return new Object({"Content-Type": "application/javascript"}); case '.pdf': return new Object({"Content-Type": "application/pdf"}); default: console.log('\n\n\t ===| ERROR: setContentType(fileExt) Defaulted out! |===\n\n'); serveStatus(200, res); return -1; } } /** * @function ServeStatus * @param {number} status * @param {Object} HTTP.response - HTTP Response Object */ function serveStatus(status, res) { let __filepath = path.join(__dirname, '/status', `/http${status}.html`); fs.readFile(__filepath, (err, data) => { if(err) { console.log('ERROR: Error serving HTTP Status'); res.writeHead(500, {"Content-Type": "text/html"}); res.write('<h1>HTTP-500: Error Serving Previous HttpStatus. ADMIN Attention Needed. Katana.Development@Gmail.com</h1>') res.end(); } res.writeHead(status, {"Content-Type": "text/html"}); res.write(data); res.end(); }); } //* ========| serv.js's: 'Modular Exports' |======== module.exports.Backend = Backend; module.exports.getContentType = getContentType; module.exports.printEzRead = printEzRead; module.exports.serveStatus = serveStatus;