am-serv
Version:
AbstractMechanics is a framework developed by Andrew Chamber's small group of side projects called Katana Development. Its meant to have a small small footprint, be easy to use, yet powerfull when developing complex websites, and web-applications.
273 lines (206 loc) • 9.59 kB
JavaScript
/*-----------------------------------------------------------------------------------*
* ----APPLICATION-HTTP-SERVER---- *
* Program: AbstractMechanics *
* Developer: Katana Developmenr *
* Created On: 15-JUNE-2020 *
* ----- ----- ----- ----- ----- ----- ----- *
* This is a NodeJS Framework for creating moderatly complex web applications. *
*-----------------------------------------------------------------------------------*/
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const events = require('events');
const {on} = require('process');
const ee = new events.EventEmitter();
class ApplicationServer {
/** ______________________________________________________________________________________
* @constructor The constructor for this Object can be looked at as a/the 'HTTP-SERVER'.
* @memberof ApplicationServer
* @param {number} port Example: ['HTTP://localhost:8080/'] <-- port = 8080;
* @param {string} approot file for this applications root folder/directory
* _______________________________________________________________________________________
***/
constructor(port, approot) {
this.port = port;
this.approot = approot;
http.createServer(this.onRequest).listen(port);
printStuffNicely('ServerCreated', `\nApplication Server Listening on: ${this.port}`,);
}
/** _______________________________________________
* @method onRequest()
* @memberof ApplicationServer
* @param {object} request HTTP Request Data
* @param {object} response HTTP Response Data
* _______________________________________________
***/
onRequest(request, response) {
const parsedRequest = parseHttpRequest(request);
switch(request.method.toUpperCase()) {
case 'GET':
printStuffNicely('GET REQUEST RECIEVED', parsedRequest);
let event = 'EventUrl_' + parsedRequest.pathname;
let eventCount = ee.listenerCount(event);
if(eventCount > 0) ee.emit(event, parsedRequest.contenttype, response);
else {
event = 'EventDirectory_' + parsedRequest.dirname;
eventCount = ee.listenerCount(event);
if(eventCount > 0) ee.emit(event, parsedRequest, response);
else err_displayStatus(400, response);
}
break;
case 'POST':
printStuffNicely('POST REQUEST RECIEVED', parsedRequest);
let ev = 'EventForm_' + parsedRequest.pathname;
ee.emit(ev, response);
break;
};
};
formProccess(url, fn, callback)
{
var event = 'EventForm_' + url;
ee.on(event, (response)=>
{
printStuffNicely('FORM PROC EVENT TRIGGERED');
callback(fn);
})
}
/** _________________________________________________________________________
* @method url()
* @memberof ApplicationServer
* @param {string} url choose a url.
* @param {string} file choose file to read and serve when url is requested.
* _________________________________________________________________________
***/
url(url, file) {
var event = 'EventUrl_' + url;
ee.on(event, (contenttype, response) => {
printStuffNicely(`URL Event Triggered`, `URl: ${url}`, `FILE: ${file}`);
let __fullfilepath = path.join(this.approot, file);
if(fs.existsSync)
{
fs.readFile(__fullfilepath, (err, data) => {
response.writeHead(200, contenttype);
response.write(data);
response.end();
return 0;
});
}
else err_displayStatus(404, response);
});
}
/** ____________________________________________________________________
* @method directory()
* @memberof ApplicationServer
* @param {string} url url to use as a prefix to directories filenames.
* @param {string} dir choose a directory to serve files from.
* ____________________________________________________________________
***/
directory(url, dir) {
var event = 'EventDirectory_' + url;
ee.on(event, (parsedRequest, response) => {
console.log('EVENT TRIGGERED DIRECTORY');
var __fullpath = path.join(this.approot, dir, parsedRequest.filename);
fs.readFile(__fullpath, (err, data) => {
if(err) console.error('ERROR OCCURED WHILE ATTEMPTING TO READ A FILE');
response.writeHead(200, parsedRequest.contenttype);
response.write(data);
response.end();
});
});
}
}//! <--------------------[ EndOfClass ApplicationServer ]-------------------->
//? Stand-alone functions not a part of, but used by, the Class: 'ApplicationServer'.
//? ==================================================================================
/** ----------------------------
* @function parseHttpRequest()
* @param {*} req
* ----------------------------
**/
function parseHttpRequest(req) {
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: setContentType(path.extname(reqPathname)),
cookies: req.headers.cookie
};
return parsedHttpRequest;
}
/** -----------------------------------------------------------------------------
* @function setContentType()
* @param {string} fileExt Part of filename that comes after the dot operator.
* ---------------------------------------------------------------------------
***/
function setContentType(fileExt) {
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');
return new Object({"Content-Type": "text/html"});
}
}
/*** ----------------------------------------------------------------------------
* @param {number} code HTTP Status code
* @param {object} response HTTP response object returned during 'HTTP' request.
* -----------------------------------------------------------------------------
***/
function err_displayStatus(code, response) {
let __fullpath = path.join(__dirname, `/httpStatusView/http${code}.html`);
console.log(`ERROR: HTTP-${code}`);
fs.readFile(__fullpath, (err, data) => {
response.writeHead(code, {"Content-Type": "text/html"});
response.write(data);
response.end();
});
}
/** ----------------------------------------------------------------------------
* @function printStuffNicely();
* @param {string} header Prints as Header
* @param {any} arguments prints all extra arguments
* ----------------------------------------------------------------------------
***/
function printStuffNicely(header) {
let values = Object.values(arguments);
console.log(`\n\n\n\t\t===============|| ${header} ||===============`);
values.forEach((value, i) => {
if(i !== 0) {
console.log(value);
}
});
return 0;
};
/*
? ============[ Function & Class Exports ]============
*/
module.exports.ApplicationServer = ApplicationServer;
module.exports.printStuffNicely = printStuffNicely;
module.exports.setContentType = setContentType;
module.exports.err_displayStatus = err_displayStatus;