From d468c5af92ca03ae85083ae1c1325fc630034df3 Mon Sep 17 00:00:00 2001 From: Jack Clark Date: Wed, 31 Jan 2018 17:07:29 +0000 Subject: [PATCH 1/5] initial move of routes to fastify --- acmeaircmd/index.js | 4 +- app.js | 192 ++++++++++++++++++++++----------------- loader/loader.js | 18 ++-- netflix/hystrix/index.js | 23 +++-- package.json | 27 +++--- routes/index.js | 143 ++++++++++++++--------------- 6 files changed, 221 insertions(+), 186 deletions(-) diff --git a/acmeaircmd/index.js b/acmeaircmd/index.js index 97e2c47..3f8057d 100644 --- a/acmeaircmd/index.js +++ b/acmeaircmd/index.js @@ -19,8 +19,8 @@ module.exports = function (authService,settings) { var hystrix = require('../netflix/hystrix/index.js'); var command = require('../netflix/hystrix/command.js'); - module.hystrixStream = function(request, response){ - hystrix.hystrixStream(request, response); + module.hystrixStream = function(request, reply){ + hystrix.hystrixStream(request, reply); } module.createSession = function(userid, callback /* (error, sessionId) */){ diff --git a/app.js b/app.js index 38e071a..fa21a8b 100644 --- a/app.js +++ b/app.js @@ -14,12 +14,14 @@ * limitations under the License. *******************************************************************************/ -var express = require('express') - , http = require('http') +var Fastify = require('fastify') , fs = require('fs') - , log4js = require('log4js'); + , log4js = require('log4js') + , path = require('path'); var settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); + + var logger = log4js.getLogger('app'); logger.setLevel(settings.loggerLevel); @@ -62,64 +64,83 @@ if(process.env.VCAP_SERVICES){ } logger.info("db type=="+dbtype); -var routes = new require('./routes/index.js')(dbtype, authService,settings); +var routes = new require('./routes/index.js')(dbtype, authService, settings); var loader = new require('./loader/loader.js')(routes, settings); +// Setup fastify +var fastify = Fastify({ logger: settings.useDevLogger ? true : false }) // log every request to the console in development + +fastify.register(require('fastify-static'), { + root: path.join(__dirname, 'public') // set the static files location /public/img will be /img for users +}); + +fastify.register(require('fastify-cookie')) +fastify.register(require('fastify-formbody')) + // Setup express with 4.0.0 -var app = express(); -var morgan = require('morgan'); -var bodyParser = require('body-parser'); -var methodOverride = require('method-override'); -var cookieParser = require('cookie-parser') - -app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users -if (settings.useDevLogger) - app.use(morgan('dev')); // log every request to the console - -//create application/json parser -var jsonParser = bodyParser.json(); -// create application/x-www-form-urlencoded parser -var urlencodedParser = bodyParser.urlencoded({ extended: false }); - -app.use(jsonParser); -app.use(urlencodedParser); -//parse an HTML body into a string -app.use(bodyParser.text({ type: 'text/html' })); - -app.use(methodOverride()); // simulate DELETE and PUT -app.use(cookieParser()); // parse cookie - -var router = express.Router(); - -router.post('/login', login); -router.get('/login/logout', logout); -router.post('/flights/queryflights', routes.checkForValidSessionCookie, routes.queryflights); -router.post('/bookings/bookflights', routes.checkForValidSessionCookie, routes.bookflights); -router.post('/bookings/cancelbooking', routes.checkForValidSessionCookie, routes.cancelBooking); -router.get('/bookings/byuser/:user', routes.checkForValidSessionCookie, routes.bookingsByUser); -router.get('/customer/byid/:user', routes.checkForValidSessionCookie, routes.getCustomerById); -router.post('/customer/byid/:user', routes.checkForValidSessionCookie, routes.putCustomerById); -router.get('/config/runtime', routes.getRuntimeInfo); -router.get('/config/dataServices', routes.getDataServiceInfo); -router.get('/config/activeDataService', routes.getActiveDataServiceInfo); -router.get('/config/countBookings', routes.countBookings); -router.get('/config/countCustomers', routes.countCustomer); -router.get('/config/countSessions', routes.countCustomerSessions); -router.get('/config/countFlights', routes.countFlights); -router.get('/config/countFlightSegments', routes.countFlightSegments); -router.get('/config/countAirports' , routes.countAirports); -//router.get('/loaddb', startLoadDatabase); -router.get('/loader/load', startLoadDatabase); -router.get('/loader/query', loader.getNumConfiguredCustomers); -router.get('/checkstatus', checkStatus); +// var app = express(); +// var morgan = require('morgan'); +// var bodyParser = require('body-parser'); +// var methodOverride = require('method-override'); +// var cookieParser = require('cookie-parser') + +// app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users +// if (settings.useDevLogger) +// app.use(morgan('dev')); // log every request to the console + +// //create application/json parser +// var jsonParser = bodyParser.json(); +// // create application/x-www-form-urlencoded parser +// var urlencodedParser = bodyParser.urlencoded({ extended: false }); + +// app.use(jsonParser); +// app.use(urlencodedParser); +// //parse an HTML body into a string +// app.use(bodyParser.text({ type: 'text/html' })); + +// app.use(methodOverride()); // simulate DELETE and PUT +// app.use(cookieParser()); // parse cookie + +// var router = express.Router(); + +function router (fastify, opts, next) { + fastify.post('/login', {}, login); // @todo this doesn't work yet + fastify.get('/login/logout', {}, logout); + fastify.post('/flights/queryflights', { beforeHandler: routes.checkForValidSessionCookie }, routes.queryflights); + fastify.post('/bookings/bookflights', { beforeHandler: routes.checkForValidSessionCookie }, routes.bookflights); + fastify.post('/bookings/cancelbooking', { beforeHandler: routes.checkForValidSessionCookie }, routes.cancelBooking); + fastify.get('/bookings/byuser/:user', { beforeHandler: routes.checkForValidSessionCookie }, routes.bookingsByUser); + fastify.get('/customer/byid/:user', { beforeHandler: routes.checkForValidSessionCookie }, routes.getCustomerById); + fastify.post('/customer/byid/:user', { beforeHandler: routes.checkForValidSessionCookie }, routes.putCustomerById); + fastify.get('/config/runtime', {}, routes.getRuntimeInfo); + fastify.get('/config/dataServices', {}, routes.getDataServiceInfo); + fastify.get('/config/activeDataService', {}, routes.getActiveDataServiceInfo); + fastify.get('/config/countBookings', {}, routes.countBookings); + fastify.get('/config/countCustomers', {}, routes.countCustomer); + fastify.get('/config/countSessions', {}, routes.countCustomerSessions); + fastify.get('/config/countFlights', {}, routes.countFlights); + fastify.get('/config/countFlightSegments', {}, routes.countFlightSegments); + fastify.get('/config/countAirports', {}, routes.countAirports); + // fastify.get('/loaddb', startLoadDatabase); + fastify.get('/loader/load', {}, startLoadDatabase); + fastify.get('/loader/query', {}, loader.getNumConfiguredCustomers); + fastify.get('/checkstatus', {}, checkStatus); + + next() +} if (authService && authService.hystrixStream) - app.get('/rest/api/hystrix.stream', authService.hystrixStream); + fastify.get('/rest/api/hystrix.stream', authService.hystrixStream); + + +// //REGISTER OUR ROUTES so that all of routes will have prefix +// app.use(settings.contextRoot, router); +fastify.register(router, { + prefix: settings.contextRoot +}) -//REGISTER OUR ROUTES so that all of routes will have prefix -app.use(settings.contextRoot, router); // Only initialize DB after initialization of the authService is done var initialized = false; @@ -135,60 +156,67 @@ else initDB(); -function checkStatus(req, res){ - res.sendStatus(200); +function checkStatus(req, reply) { + reply.send('OK'); } -function login(req, res){ - if (!initialized) - { +function login(req, reply) { + if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - res.sendStatus(403); - }else - routes.login(req, res); + reply.status(403).send('Forbidden'); + } else { + routes.login(req, reply); + } } -function logout(req, res){ +function logout(req, reply){ if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - res.sendStatus(400); + reply.status(400).send('Bad request'); }else - routes.logout(req, res); + routes.logout(req, reply); } -function startLoadDatabase(req, res){ +function startLoadDatabase(req, reply){ if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - res.sendStatus(400); + reply.status(400).send('Bad request'); }else - loader.startLoadDatabase(req, res); + loader.startLoadDatabase(req, reply); } function initDB(){ - if (initialized ) return; - routes.initializeDatabaseConnections(function(error) { - if (error) { - logger.info('Error connecting to database - exiting process: '+ error); - // Do not stop the process for debug in container service - //process.exit(1); - }else - initialized =true; - - logger.info("Initialized database connections"); - startServer(); + if (initialized ) return; + routes.initializeDatabaseConnections(function(error) { + if (error) { + logger.info('Error connecting to database - exiting process: '+ error); + // Do not stop the process for debug in container service + //process.exit(1); + } else { + initialized =true; + } + + logger.info("Initialized database connections"); + startServer(); }); } function startServer() { - if (serverStarted ) return; - serverStarted = true; - app.listen(port); - logger.info("Express server listening on port " + port); + // come back to this + // if (serverStarted) return; + // serverStarted = true; + fastify.listen(port, function (err) { + if (err) { + logger.error("Error starting server " + err); + process.exit(1) + } + }); + logger.info("Fastify server listening on port " + port); } diff --git a/loader/loader.js b/loader/loader.js index 4d35b62..11b4d2b 100644 --- a/loader/loader.js +++ b/loader/loader.js @@ -127,12 +127,11 @@ module.exports = function (loadUtil,settings) { }); } - module.startLoadDatabase = function startLoadDatabase(req, res) { - if (customers.length>=1) - { - res.send('Already loaded'); + module.startLoadDatabase = function startLoadDatabase(req, reply) { + if (customers.length>=1) { + reply.send('Already loaded'); return; - } + } var numCustomers = req.query.numCustomers; if(numCustomers === undefined) { numCustomers = loaderSettings.MAX_CUSTOMERS; @@ -147,16 +146,17 @@ module.exports = function (loadUtil,settings) { flightQueue.drain = function() { logger.info('all flights loaded'); logger.info('ending loading database'); - res.send('Database Finished Loading'); + reply.send('Database Finished Loading'); }; customerQueue.push(customers); }); //res.send('Trigger DB loading'); } - module.getNumConfiguredCustomers = function (req, res) { - res.contentType("text/plain"); - res.send(loaderSettings.MAX_CUSTOMERS.toString()); + module.getNumConfiguredCustomers = function (req, reply) { + res + .type("text/plain") + .send(loaderSettings.MAX_CUSTOMERS.toString()); } diff --git a/netflix/hystrix/index.js b/netflix/hystrix/index.js index 7f65254..156fa66 100644 --- a/netflix/hystrix/index.js +++ b/netflix/hystrix/index.js @@ -9,11 +9,11 @@ exports.setHystrixMetricsStreamHandlerFactory = function(handler){ hystrixMetricsStreamHandlerFactory= handler; } -exports.hystrixStream = function(request, response) { +exports.hystrixStream = function(request, reply) { if (!hystrixMetricsStreamHandlerFactory) { - response.send(503,{error:"hystrixMetricsStreamHandlerFactory not defined."}); + reply.status(503).send({error:"hystrixMetricsStreamHandlerFactory not defined."}); return; } @@ -22,10 +22,10 @@ exports.hystrixStream = function(request, response) { hystrixMetricsStreamHandlerFactory.getHystrixMetricsStreamHandler(refreshInterval, function(error, instance){ if (!instance ){ console.log("Can not get instance"); - response.send(503, {error: 'Can not get instance'}); + reply.status(503).send({error: 'Can not get instance'}); }else if (error){ console.log("Get instance hit error:"+error); - response.send(503, {error: error}); + reply.status(503).send({error: error}); }else { //End is never called now. Where else I can shutdown the instances which will the connection count??? request.on('end', function() { @@ -33,20 +33,23 @@ exports.hystrixStream = function(request, response) { instance.shutdown(function(){ }) }); /* initialize response */ - response.setHeader("Content-Type", "text/event-stream;charset=UTF-8"); - response.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); - response.setHeader("Pragma", "no-cache"); + reply.header("Content-Type", "text/event-stream;charset=UTF-8"); + reply.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); + reply.header("Pragma", "no-cache"); setInterval(function(){ instance.getJsonMessageAsString(function(err,jsonMessageStr){ if (err) { console.log("error:"+err); - response.send(503,{error: err}); + reply.status(503).send({error: err}); } else { if (jsonMessageStr.length==0) { - response.write("ping: \n"); + reply.send("ping: \n") + // @todo send this as a stream. + // response.write("ping: \n"); } else { - response.write(jsonMessageStr); // use write instead of send so the request is not ended + reply.send(jsonMessageStr); + // response.write(jsonMessageStr); // use write instead of send so the request is not ended } // NodeJS http does not have a flushBuffer function } diff --git a/package.json b/package.json index 54181fa..6f71dff 100644 --- a/package.json +++ b/package.json @@ -6,21 +6,24 @@ "start": "node app.js" }, "dependencies": { - "async": "0.2.x", - "express": "4.11.x", - "morgan": "1.5.x", + "async": "0.2.10", "body-parser": "1.11.x", - "method-override": "2.3.x", + "cassandra-driver": "2.0.x", + "circuit-breaker": "0.0.4", "cookie-parser": "1.3.x", - "mongodb": "2.0.x", - "node-uuid":"1.3.3", - "async": "0.2.10", "csv": "0.2.4", + "express": "4.11.x", + "fastify": "^0.41.0", + "fastify-cookie": "^1.2.0", + "fastify-formbody": "^1.2.3", + "fastify-static": "^0.6.0", "log4js": "0.6.12", - "ttl-lru-cache": "0.0.2", - "nano":"5.10.x", - "cassandra-driver":"2.0.x", - "stats-lite":"1.0.3", - "circuit-breaker":"0.0.4" + "method-override": "2.3.x", + "mongodb": "2.0.x", + "morgan": "1.5.x", + "nano": "5.10.x", + "node-uuid": "1.3.3", + "stats-lite": "1.0.3", + "ttl-lru-cache": "0.0.2" } } diff --git a/routes/index.js b/routes/index.js index 17560bf..b64a070 100644 --- a/routes/index.js +++ b/routes/index.js @@ -39,7 +39,7 @@ module.exports = function (dbtype, authService, settings) { dataaccess.insertOne(collectionname, doc, callback) }; - module.checkForValidSessionCookie = function(req, res, next) { + module.checkForValidSessionCookie = function(req, reply, done) { logger.debug('checkForValidCookie'); var sessionid = req.cookies.sessionid; if (sessionid) { @@ -47,74 +47,73 @@ module.exports = function (dbtype, authService, settings) { } if (!sessionid || sessionid == '') { logger.debug('checkForValidCookie - no sessionid cookie so returning 403'); - res.sendStatus(403); + reply.status(403).send('Forbidden'); return; } validateSession(sessionid, function(err, customerid) { if (err) { logger.debug('checkForValidCookie - system error validating session so returning 500'); - res.sendStatus(500); + reply.status(500).send('Internal Server Eror'); return; } if (customerid) { - logger.debug('checkForValidCookie - good session so allowing next route handler to be called'); + logger.debug('checkForValidCookie - good session so allowing done route handler to be called'); req.acmeair_login_user = customerid; - next(); + done(); return; } else { logger.debug('checkForValidCookie - bad session so returning 403'); - res.sendStatus(403); + reply.status(403).send('Forbidden'); return; } }); } - module.login = function(req, res) { + module.login = function(req, reply) { logger.debug('logging in user'); var login = req.body.login; var password = req.body.password; - res.cookie('sessionid', ''); + reply.setCookie('sessionid', ''); // replace eventually with call to business logic to validate customer validateCustomer(login, password, function(err, customerValid) { if (err) { - res.send(500,err); // TODO: do I really need this or is there a cleaner way?? + reply.status(500).send(err); // TODO: do I really need this or is there a cleaner way?? return; } if (!customerValid) { - res.sendStatus(403); + reply.status(403).send('Forbidden'); } else { createSession(login, function(error, sessionid) { if (error) { logger.info(error); - res.send(500, error); + res.status(500).send(error); return; } - res.cookie('sessionid', sessionid); - res.send('logged in'); + reply.setCookie('sessionid', sessionid); + reply.send('logged in'); }); } }); }; - module.logout = function(req, res) { + module.logout = function(req, reply) { logger.debug('logging out user'); var sessionid = req.cookies.sessionid; - var login = req.body.login; invalidateSession(sessionid, function(err) { - res.cookie('sessionid', ''); - res.send('logged out'); + reply.setCookie('sessionid', ''); + reply.send('logged out'); }); }; - module.queryflights = function(req, res) { + module.queryflights = function(req, reply) { logger.debug('querying flights'); var fromAirport = req.body.fromAirport; @@ -154,7 +153,7 @@ module.exports = function (dbtype, authService, settings) { {"numPages":1,"flightsOptions": flightsOutbound,"currentPage":0,"hasMoreOptions":false,"pageSize":10}, {"numPages":1,"flightsOptions": flightsReturn,"currentPage":0,"hasMoreOptions":false,"pageSize":10} ], "tripLegs":2}; - res.send(options); + reply.send(options); }); } else { @@ -162,12 +161,12 @@ module.exports = function (dbtype, authService, settings) { [ {"numPages":1,"flightsOptions": flightsOutbound,"currentPage":0,"hasMoreOptions":false,"pageSize":10} ], "tripLegs":1}; - res.send(options); + reply.send(options); } }); }; - module.bookflights = function(req, res) { + module.bookflights = function(req, reply) { logger.debug('booking flights'); var userid = req.body.userid; @@ -181,19 +180,21 @@ module.exports = function (dbtype, authService, settings) { if (!oneWay) { bookFlight(retFlight, userid, function (error, retBookingId) { var bookingInfo = {"oneWay":false,"returnBookingId":retBookingId,"departBookingId":toBookingId}; - res.header('Cache-Control', 'no-cache'); - res.send(bookingInfo); + reply + .header('Cache-Control', 'no-cache') + .send(bookingInfo); }); } else { var bookingInfo = {"oneWay":true,"departBookingId":toBookingId}; - res.header('Cache-Control', 'no-cache'); - res.send(bookingInfo); + reply + .header('Cache-Control', 'no-cache') + .send(bookingInfo); } }); }; - module.cancelBooking = function(req, res) { + module.cancelBooking = function(req, reply) { logger.debug('canceling booking'); var number = req.body.number; @@ -201,44 +202,44 @@ module.exports = function (dbtype, authService, settings) { cancelBooking(number, userid, function (error) { if (error) { - res.send({'status':'error'}); + reply.send({'status':'error'}); } else { - res.send({'status':'success'}); + reply.send({'status':'success'}); } }); }; - module.bookingsByUser = function(req, res) { + module.bookingsByUser = function(req, reply) { logger.debug('listing booked flights by user ' + req.params.user); getBookingsByUser(req.params.user, function(err, bookings) { if (err) { - res.sendStatus(500); + reply.status(500).send('Internal Server Error'); } - res.send(bookings); + reply.send(bookings); }); }; - module.getCustomerById = function(req, res) { + module.getCustomerById = function(req, reply) { logger.debug('getting customer by user ' + req.params.user); getCustomer(req.params.user, function(err, customer) { if (err) { - res.sendStatus(500); + reply.status(500).send('Internal Server Error'); } - res.send(customer); + reply.send(customer); }); }; - module.putCustomerById = function(req, res) { + module.putCustomerById = function(req, reply) { logger.debug('putting customer by user ' + req.params.user); updateCustomer(req.params.user, req.body, function(err, customer) { if (err) { - res.sendStatus(500); + reply.status(500).send('Internal Server Error'); } - res.send(customer); + reply.send(customer); }); }; @@ -248,84 +249,84 @@ module.exports = function (dbtype, authService, settings) { res.send(now); }; - module.getRuntimeInfo = function(req,res) { + module.getRuntimeInfo = function(req, reply) { var runtimeInfo = []; runtimeInfo.push({"name":"Runtime","description":"NodeJS"}); var versions = process.versions; for (var key in versions) { runtimeInfo.push({"name":key,"description":versions[key]}); } - res.contentType('application/json'); - res.send(JSON.stringify(runtimeInfo)); + // res.contentType('application/json'); + reply.send(JSON.stringify(runtimeInfo)); }; - module.getDataServiceInfo = function(req,res) { + module.getDataServiceInfo = function(req, reply) { var dataServices = [{"name":"cassandra","description":"Apache Cassandra NoSQL DB"}, {"name":"cloudant","description":"IBM Distributed DBaaS"}, {"name":"mongo","description":"MongoDB NoSQL DB"}]; - res.send(JSON.stringify(dataServices)); + reply.send(JSON.stringify(dataServices)); }; - module.getActiveDataServiceInfo = function (req,res) { - res.send(dbtype); + module.getActiveDataServiceInfo = function (req, reply) { + reply.send(dbtype); }; - module.countBookings = function(req,res) { - countItems(module.dbNames.bookingName, function (error,count){ - if (error){ - res.send("-1"); + module.countBookings = function(req, reply) { + countItems(module.dbNames.bookingName, function (error, count) { + if (error) { + reply.send("-1"); } else { - res.send(count.toString()); + reply.send(count.toString()); } }); }; - module.countCustomer = function(req,res) { - countItems(module.dbNames.customerName, function (error,count){ + module.countCustomer = function(req, reply) { + countItems(module.dbNames.customerName, function (error, count) { if (error){ - res.send("-1"); + reply.send("-1"); } else { - res.send(count.toString()); + reply.send(count.toString()); } }); }; - module.countCustomerSessions = function(req,res) { - countItems(module.dbNames.customerSessionName, function (error,count){ + module.countCustomerSessions = function(req, reply) { + countItems(module.dbNames.customerSessionName, function (error, count) { if (error){ - res.send("-1"); + reply.send("-1"); } else { - res.send(count.toString()); + reply.send(count.toString()); } }); }; - module.countFlights = function(req,res) { - countItems(module.dbNames.flightName, function (error,count){ - if (error){ - res.send("-1"); + module.countFlights = function(req, reply) { + countItems(module.dbNames.flightName, function (error, count) { + if (error) { + reply.send("-1"); } else { - res.send(count.toString()); + reply.send(count.toString()); } }); }; - module.countFlightSegments = function(req,res) { - countItems(module.dbNames.flightSegmentName, function (error,count){ + module.countFlightSegments = function(req, reply) { + countItems(module.dbNames.flightSegmentName, function (error, count) { if (error){ - res.send("-1"); + reply.send("-1"); } else { - res.send(count.toString()); + reply.send(count.toString()); } }); }; - module.countAirports = function(req,res) { - countItems(module.dbNames.airportCodeMappingName, function (error,count){ - if (error){ - res.send("-1"); + module.countAirports = function(req, reply) { + countItems(module.dbNames.airportCodeMappingName, function (error, count) { + if (error) { + reply.send("-1"); } else { - res.send(count.toString()); + reply.send(count.toString()); } }); }; From b77a243a135e90bb5c0a1aae18f43e0bd9616921 Mon Sep 17 00:00:00 2001 From: Jack Clark Date: Thu, 1 Feb 2018 09:36:24 +0000 Subject: [PATCH 2/5] stream reply in hystrix --- app.js | 3 +- netflix/hystrix/index.js | 64 +++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/app.js b/app.js index fa21a8b..109fe9e 100644 --- a/app.js +++ b/app.js @@ -155,9 +155,8 @@ if (authService && authService.initialize) else initDB(); - function checkStatus(req, reply) { - reply.send('OK'); + reply.send("OK"); } function login(req, reply) { diff --git a/netflix/hystrix/index.js b/netflix/hystrix/index.js index 156fa66..578754c 100644 --- a/netflix/hystrix/index.js +++ b/netflix/hystrix/index.js @@ -1,4 +1,5 @@ var fs = require('fs'); +var Stream = require('stream'); var streamHandler = require('./streamHandler.js') var settings = JSON.parse(fs.readFileSync('./netflix/hystrix.json', 'utf8')); @@ -20,43 +21,44 @@ exports.hystrixStream = function(request, reply) { console.log('setup hystrix stream with:' +refreshInterval +" ms"); hystrixMetricsStreamHandlerFactory.getHystrixMetricsStreamHandler(refreshInterval, function(error, instance){ - if (!instance ){ + if (!instance ) { console.log("Can not get instance"); reply.status(503).send({error: 'Can not get instance'}); - }else if (error){ - console.log("Get instance hit error:"+error); - reply.status(503).send({error: error}); - }else { - //End is never called now. Where else I can shutdown the instances which will the connection count??? - request.on('end', function() { - console.log('receive request end'); - instance.shutdown(function(){ }) - }); - /* initialize response */ - reply.header("Content-Type", "text/event-stream;charset=UTF-8"); - reply.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); - reply.header("Pragma", "no-cache"); + } else if (error) { + console.log("Get instance hit error:"+error); + reply.status(503).send({error: error}); + } else { + //End is never called now. Where else I can shutdown the instances which will the connection count??? + request.on('end', function() { + console.log('receive request end'); + instance.shutdown(function(){ }) + }); + /* initialize response */ + reply.header("Content-Type", "text/event-stream;charset=UTF-8"); + reply.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); + reply.header("Pragma", "no-cache"); + var stream = new Stream; + stream.readable = true; - setInterval(function(){ - instance.getJsonMessageAsString(function(err,jsonMessageStr){ - if (err) { - console.log("error:"+err); + setInterval(function(){ + instance.getJsonMessageAsString(function(err, jsonMessageStr) { + if (err) { + console.log("error:"+err); reply.status(503).send({error: err}); - } else { + } else { if (jsonMessageStr.length==0) { - reply.send("ping: \n") - // @todo send this as a stream. - // response.write("ping: \n"); - } else { - reply.send(jsonMessageStr); - // response.write(jsonMessageStr); // use write instead of send so the request is not ended - } + stream.emit("data", "ping: \n") + } else { + stream.emit("data", jsonMessageStr); + } // NodeJS http does not have a flushBuffer function - } - }); - },refreshInterval) - } - }) + } + }); + + reply.send(stream) + }, refreshInterval) + } + }) } exports.getHystrixMetricsStreamHandler = function(refreshInterval, callback /*error, handler*/){ From ce29e01041b525d117ae2138c001824faeb44d16 Mon Sep 17 00:00:00 2001 From: Jack Clark Date: Thu, 1 Feb 2018 16:46:11 +0000 Subject: [PATCH 3/5] finish initial move to fastify, remove express module --- app.js | 54 ++++---------------- authservice_app.js | 106 +++++++++++++++++++-------------------- loader/loader.js | 2 +- netflix/hystrix/index.js | 19 ++++--- package.json | 1 - routes/index.js | 40 +++++++-------- 6 files changed, 95 insertions(+), 127 deletions(-) diff --git a/app.js b/app.js index 109fe9e..c460a89 100644 --- a/app.js +++ b/app.js @@ -20,8 +20,6 @@ var Fastify = require('fastify') , path = require('path'); var settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); - - var logger = log4js.getLogger('app'); logger.setLevel(settings.loggerLevel); @@ -33,7 +31,7 @@ logger.info("host:port=="+host+":"+port); var authService; var authServiceLocation = process.env.AUTH_SERVICE; -if (authServiceLocation) +if (authServiceLocation) { logger.info("Use authservice:"+authServiceLocation); var authModule; @@ -41,7 +39,7 @@ if (authServiceLocation) authModule = "acmeairhttp"; else authModule= authServiceLocation; - + authService = new require('./'+authModule+'/index.js')(settings); if (authService && "true"==process.env.enableHystrix) // wrap into command pattern { @@ -67,7 +65,7 @@ logger.info("db type=="+dbtype); var routes = new require('./routes/index.js')(dbtype, authService, settings); var loader = new require('./loader/loader.js')(routes, settings); -// Setup fastify +// Setup fastify var fastify = Fastify({ logger: settings.useDevLogger ? true : false }) // log every request to the console in development fastify.register(require('fastify-static'), { @@ -77,33 +75,6 @@ fastify.register(require('fastify-static'), { fastify.register(require('fastify-cookie')) fastify.register(require('fastify-formbody')) -// Setup express with 4.0.0 - -// var app = express(); -// var morgan = require('morgan'); -// var bodyParser = require('body-parser'); -// var methodOverride = require('method-override'); -// var cookieParser = require('cookie-parser') - -// app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users -// if (settings.useDevLogger) -// app.use(morgan('dev')); // log every request to the console - -// //create application/json parser -// var jsonParser = bodyParser.json(); -// // create application/x-www-form-urlencoded parser -// var urlencodedParser = bodyParser.urlencoded({ extended: false }); - -// app.use(jsonParser); -// app.use(urlencodedParser); -// //parse an HTML body into a string -// app.use(bodyParser.text({ type: 'text/html' })); - -// app.use(methodOverride()); // simulate DELETE and PUT -// app.use(cookieParser()); // parse cookie - -// var router = express.Router(); - function router (fastify, opts, next) { fastify.post('/login', {}, login); // @todo this doesn't work yet fastify.get('/login/logout', {}, logout); @@ -134,14 +105,12 @@ if (authService && authService.hystrixStream) fastify.get('/rest/api/hystrix.stream', authService.hystrixStream); -// //REGISTER OUR ROUTES so that all of routes will have prefix -// app.use(settings.contextRoot, router); +// REGISTER OUR ROUTES so that all of routes will have prefix fastify.register(router, { prefix: settings.contextRoot }) - // Only initialize DB after initialization of the authService is done var initialized = false; var serverStarted = false; @@ -163,7 +132,7 @@ function login(req, reply) { if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - reply.status(403).send('Forbidden'); + reply.code(403).send('Forbidden'); } else { routes.login(req, reply); } @@ -174,7 +143,7 @@ function logout(req, reply){ { logger.info("please wait for db connection initialized then trigger again."); initDB(); - reply.status(400).send('Bad request'); + reply.code(400).send('Bad request'); }else routes.logout(req, reply); } @@ -185,7 +154,7 @@ function startLoadDatabase(req, reply){ { logger.info("please wait for db connection initialized then trigger again."); initDB(); - reply.status(400).send('Bad request'); + reply.code(400).send('Bad request'); }else loader.startLoadDatabase(req, reply); } @@ -196,7 +165,7 @@ function initDB(){ if (error) { logger.info('Error connecting to database - exiting process: '+ error); // Do not stop the process for debug in container service - //process.exit(1); + //process.exit(1); } else { initialized =true; } @@ -208,14 +177,13 @@ function initDB(){ function startServer() { - // come back to this - // if (serverStarted) return; - // serverStarted = true; + if (serverStarted) return; + serverStarted = true; fastify.listen(port, function (err) { if (err) { logger.error("Error starting server " + err); process.exit(1) } - }); + }); logger.info("Fastify server listening on port " + port); } diff --git a/authservice_app.js b/authservice_app.js index 4c8553e..f34c8ce 100644 --- a/authservice_app.js +++ b/authservice_app.js @@ -15,6 +15,7 @@ *******************************************************************************/ var fs = require('fs'); +var Fastify = require('fastify'); var settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); var log4js = require('log4js'); var logger = log4js.getLogger('authservice_app'); @@ -42,22 +43,21 @@ logger.info("db type=="+dbtype); var routes = new require('./authservice/routes/index.js')(dbtype,settings); // call the packages we need -var express = require('express'); -var app = express(); -var morgan = require('morgan'); +var fastify = Fastify({ logger: settings.useDevLogger ? true : false }) // log every request to the console in development -if (settings.useDevLogger) - app.use(morgan('dev')); // log every request to the console +function router (fastify, opts, next) { + fastify.post('/byuserid/:user', {}, createToken); + fastify.get('/:tokenid', {}, validateToken); + fastify.get('/status', {}, checkStatus); + fastify.delete('/:tokenid', {}, invalidateToken); -var router = express.Router(); - -router.post('/byuserid/:user', createToken); -router.get('/:tokenid', validateToken); -router.get('/status', checkStatus); -router.delete('/:tokenid', invalidateToken); + next(); +} // REGISTER OUR ROUTES so that all of routes will have prefix -app.use(settings.authContextRoot+'/authtoken', router); +fastify.register(router, { + prefix: settings.contextRoot +}) var initialized = false; var serverStarted = false; @@ -82,71 +82,69 @@ function initDB(){ function startServer() { - if (serverStarted ) return; + if (serverStarted) return; serverStarted = true; - app.listen(port); + fastify.listen(port, function (err) { + if (err) { + logger.error("Error starting server " + err); + process.exit(1) + } + }); console.log('Application started port ' + port); } -function checkStatus(req, res){ - res.sendStatus(200); +function checkStatus(req, reply){ + reply.send("OK"); } -function createToken(req, res){ +function createToken(req, reply){ logger.debug('create token by user ' + req.params.user); - if (!initialized) - { + if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - res.send(403); - }else - { - routes.createSessionInDB(req.params.user, function(error, cs){ - if (error){ - res.status(404).send(error); - } - else{ - res.send(JSON.stringify(cs)); - } - }) + reply.code(403).send("Forbidden"); + } else { + routes.createSessionInDB(req.params.user, function(error, cs) { + if (error) { + reply.code(404).send(error); + } else { + reply.send(JSON.stringify(cs)); + } + }) } } function validateToken(req, res){ logger.debug('validate token ' + req.params.tokenid); - if (!initialized) - { + if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - res.send(403); - }else - { + reply.code(403).send("Forbidden"); + } else { routes.validateSessionInDB(req.params.tokenid, function(error, cs){ - if (error){ - res.status(404).send(error); - } - else{ - res.send(JSON.stringify(cs)); - } - }) + if (error) { + reply.code(404).send(error); + } else { + reply.send(JSON.stringify(cs)); + } + }) } } -function invalidateToken(req, res){ +function invalidateToken(req, reply){ logger.debug('invalidate token ' + req.params.tokenid); - if (!initialized) - { + if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); - res.send(403); - }else - { - routes.invalidateSessionInDB(req.params.tokenid, function(error){ - if (error){ - res.status(404).send(error); - } - else res.sendStatus(200); - }) + reply.code(403).send("Forbidden"); + } else { + routes.invalidateSessionInDB(req.params.tokenid, function(error) { + if (error) { + reply.code(404).send(error); + } else { + reply.sendStatus(200); + } + }) } } diff --git a/loader/loader.js b/loader/loader.js index 11b4d2b..15e60c9 100644 --- a/loader/loader.js +++ b/loader/loader.js @@ -154,7 +154,7 @@ module.exports = function (loadUtil,settings) { } module.getNumConfiguredCustomers = function (req, reply) { - res + reply .type("text/plain") .send(loaderSettings.MAX_CUSTOMERS.toString()); } diff --git a/netflix/hystrix/index.js b/netflix/hystrix/index.js index 578754c..81f7219 100644 --- a/netflix/hystrix/index.js +++ b/netflix/hystrix/index.js @@ -14,21 +14,23 @@ exports.hystrixStream = function(request, reply) { if (!hystrixMetricsStreamHandlerFactory) { - reply.status(503).send({error:"hystrixMetricsStreamHandlerFactory not defined."}); + reply.code(503).send({error:"hystrixMetricsStreamHandlerFactory not defined."}); return; } console.log('setup hystrix stream with:' +refreshInterval +" ms"); hystrixMetricsStreamHandlerFactory.getHystrixMetricsStreamHandler(refreshInterval, function(error, instance){ - if (!instance ) { + console.log('getHystrixMetricsStreamHandler') + + if (!instance) { console.log("Can not get instance"); - reply.status(503).send({error: 'Can not get instance'}); + reply.code(503).send({error: 'Can not get instance'}); } else if (error) { console.log("Get instance hit error:"+error); - reply.status(503).send({error: error}); + reply.code(503).send({error: error}); } else { - //End is never called now. Where else I can shutdown the instances which will the connection count??? + // End is never called now. Where else I can shutdown the instances which will the connection count??? request.on('end', function() { console.log('receive request end'); instance.shutdown(function(){ }) @@ -37,6 +39,7 @@ exports.hystrixStream = function(request, reply) { reply.header("Content-Type", "text/event-stream;charset=UTF-8"); reply.header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); reply.header("Pragma", "no-cache"); + var stream = new Stream; stream.readable = true; @@ -44,7 +47,7 @@ exports.hystrixStream = function(request, reply) { instance.getJsonMessageAsString(function(err, jsonMessageStr) { if (err) { console.log("error:"+err); - reply.status(503).send({error: err}); + reply.code(503).send({error: err}); } else { if (jsonMessageStr.length==0) { stream.emit("data", "ping: \n") @@ -54,9 +57,9 @@ exports.hystrixStream = function(request, reply) { // NodeJS http does not have a flushBuffer function } }); - - reply.send(stream) }, refreshInterval) + + reply.send(stream) } }) } diff --git a/package.json b/package.json index 6f71dff..bb66c4a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "circuit-breaker": "0.0.4", "cookie-parser": "1.3.x", "csv": "0.2.4", - "express": "4.11.x", "fastify": "^0.41.0", "fastify-cookie": "^1.2.0", "fastify-formbody": "^1.2.3", diff --git a/routes/index.js b/routes/index.js index b64a070..dcd77a3 100644 --- a/routes/index.js +++ b/routes/index.js @@ -15,7 +15,7 @@ *******************************************************************************/ module.exports = function (dbtype, authService, settings) { - var module = {}; + var module = {}; var uuid = require('node-uuid'); var log4js = require('log4js'); var flightCache = require('ttl-lru-cache')({maxLength:settings.flightDataCacheMaxSize}); @@ -47,14 +47,14 @@ module.exports = function (dbtype, authService, settings) { } if (!sessionid || sessionid == '') { logger.debug('checkForValidCookie - no sessionid cookie so returning 403'); - reply.status(403).send('Forbidden'); + reply.code(403).send('Forbidden'); return; } validateSession(sessionid, function(err, customerid) { if (err) { logger.debug('checkForValidCookie - system error validating session so returning 500'); - reply.status(500).send('Internal Server Eror'); + reply.code(500).send('Internal Server Eror'); return; } @@ -66,7 +66,7 @@ module.exports = function (dbtype, authService, settings) { } else { logger.debug('checkForValidCookie - bad session so returning 403'); - reply.status(403).send('Forbidden'); + reply.code(403).send('Forbidden'); return; } }); @@ -82,18 +82,18 @@ module.exports = function (dbtype, authService, settings) { // replace eventually with call to business logic to validate customer validateCustomer(login, password, function(err, customerValid) { if (err) { - reply.status(500).send(err); // TODO: do I really need this or is there a cleaner way?? + reply.code(500).send(err); // TODO: do I really need this or is there a cleaner way?? return; } if (!customerValid) { - reply.status(403).send('Forbidden'); + reply.code(403).send('Forbidden'); } else { createSession(login, function(error, sessionid) { if (error) { logger.info(error); - res.status(500).send(error); + reply.code(500).send(error); return; } reply.setCookie('sessionid', sessionid); @@ -215,7 +215,7 @@ module.exports = function (dbtype, authService, settings) { getBookingsByUser(req.params.user, function(err, bookings) { if (err) { - reply.status(500).send('Internal Server Error'); + reply.code(500).send('Internal Server Error'); } reply.send(bookings); }); @@ -226,7 +226,7 @@ module.exports = function (dbtype, authService, settings) { getCustomer(req.params.user, function(err, customer) { if (err) { - reply.status(500).send('Internal Server Error'); + reply.code(500).send('Internal Server Error'); } reply.send(customer); }); @@ -237,16 +237,16 @@ module.exports = function (dbtype, authService, settings) { updateCustomer(req.params.user, req.body, function(err, customer) { if (err) { - reply.status(500).send('Internal Server Error'); + reply.code(500).send('Internal Server Error'); } reply.send(customer); }); }; - module.toGMTString = function(req, res) { + module.toGMTString = function(req, reply) { logger.info('******* running eyecatcher function'); var now = new Date().toGMTString(); - res.send(now); + reply.send(now); }; module.getRuntimeInfo = function(req, reply) { @@ -344,15 +344,15 @@ module.exports = function (dbtype, authService, settings) { function validateCustomer(username, password, callback /* (error, boolean validCustomer) */) { dataaccess.findOne(module.dbNames.customerName, username, function(error, customer){ - if (error) callback (error, null); - else{ - if (customer) - { - callback(null, customer.password == password); - } - else - callback(null, false) + if (error) { + callback (error, null); + } else { + if (customer) { + callback(null, customer.password == password); + } else { + callback(null, false) } + } }); }; From e923a8cfb81cc400c2c7d73d0d3d3e48f6ab8e05 Mon Sep 17 00:00:00 2001 From: Jack Clark Date: Fri, 2 Feb 2018 15:57:27 +0000 Subject: [PATCH 4/5] fastify request schema validation --- app.js | 17 ++++---- authservice_app.js | 41 +++++++++++++++--- routes/schema.js | 103 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 routes/schema.js diff --git a/app.js b/app.js index c460a89..1863e5c 100644 --- a/app.js +++ b/app.js @@ -64,6 +64,7 @@ logger.info("db type=="+dbtype); var routes = new require('./routes/index.js')(dbtype, authService, settings); var loader = new require('./loader/loader.js')(routes, settings); +var schema = require('./routes/schema.js'); // Setup fastify var fastify = Fastify({ logger: settings.useDevLogger ? true : false }) // log every request to the console in development @@ -76,14 +77,14 @@ fastify.register(require('fastify-cookie')) fastify.register(require('fastify-formbody')) function router (fastify, opts, next) { - fastify.post('/login', {}, login); // @todo this doesn't work yet - fastify.get('/login/logout', {}, logout); - fastify.post('/flights/queryflights', { beforeHandler: routes.checkForValidSessionCookie }, routes.queryflights); - fastify.post('/bookings/bookflights', { beforeHandler: routes.checkForValidSessionCookie }, routes.bookflights); - fastify.post('/bookings/cancelbooking', { beforeHandler: routes.checkForValidSessionCookie }, routes.cancelBooking); - fastify.get('/bookings/byuser/:user', { beforeHandler: routes.checkForValidSessionCookie }, routes.bookingsByUser); - fastify.get('/customer/byid/:user', { beforeHandler: routes.checkForValidSessionCookie }, routes.getCustomerById); - fastify.post('/customer/byid/:user', { beforeHandler: routes.checkForValidSessionCookie }, routes.putCustomerById); + fastify.post('/login', { schema: schema.login }, login); + fastify.get('/login/logout', { schema: schema.logout }, logout); + fastify.post('/flights/queryflights', { schema: schema.queryFlights, beforeHandler: routes.checkForValidSessionCookie }, routes.queryflights); + fastify.post('/bookings/bookflights', { schema: schema.bookFlights, beforeHandler: routes.checkForValidSessionCookie }, routes.bookflights); + fastify.post('/bookings/cancelbooking', { schema: schema.cancelBooking, beforeHandler: routes.checkForValidSessionCookie }, routes.cancelBooking); + fastify.get('/bookings/byuser/:user', { schema: schema.bookingsByUser, beforeHandler: routes.checkForValidSessionCookie }, routes.bookingsByUser); + fastify.get('/customer/byid/:user', { schema: schema.getCustomerById, beforeHandler: routes.checkForValidSessionCookie }, routes.getCustomerById); + fastify.post('/customer/byid/:user', { schema: schema.putCustomerById, beforeHandler: routes.checkForValidSessionCookie }, routes.putCustomerById); fastify.get('/config/runtime', {}, routes.getRuntimeInfo); fastify.get('/config/dataServices', {}, routes.getDataServiceInfo); fastify.get('/config/activeDataService', {}, routes.getActiveDataServiceInfo); diff --git a/authservice_app.js b/authservice_app.js index f34c8ce..0d045ec 100644 --- a/authservice_app.js +++ b/authservice_app.js @@ -42,21 +42,51 @@ logger.info("db type=="+dbtype); var routes = new require('./authservice/routes/index.js')(dbtype,settings); +var schema = { + createToken: { + params: { + type: 'object', + required: ['user'], + properties: { + user: { type: 'string' } + } + } + }, + validateToken: { + params: { + type: 'object', + required: ['tokenid'], + properties: { + tokenid: { type: 'string' } + } + } + }, + invalidateToken: { + params: { + type: 'object', + required: ['tokenid'], + properties: { + tokenid: { type: 'string' } + } + } + } +}; + // call the packages we need var fastify = Fastify({ logger: settings.useDevLogger ? true : false }) // log every request to the console in development function router (fastify, opts, next) { - fastify.post('/byuserid/:user', {}, createToken); - fastify.get('/:tokenid', {}, validateToken); + fastify.post('/byuserid/:user', { }, createToken); + fastify.get('/:tokenid', { schema: schema.validateToken }, validateToken); fastify.get('/status', {}, checkStatus); - fastify.delete('/:tokenid', {}, invalidateToken); + fastify.delete('/:tokenid', { schema: schema.invalidateToken }, invalidateToken); next(); } // REGISTER OUR ROUTES so that all of routes will have prefix fastify.register(router, { - prefix: settings.contextRoot + prefix: settings.authContextRoot + '/authtoken' }) var initialized = false; @@ -99,6 +129,7 @@ function checkStatus(req, reply){ function createToken(req, reply){ logger.debug('create token by user ' + req.params.user); + if (!initialized) { logger.info("please wait for db connection initialized then trigger again."); initDB(); @@ -142,7 +173,7 @@ function invalidateToken(req, reply){ if (error) { reply.code(404).send(error); } else { - reply.sendStatus(200); + reply.code(200).send('OK'); } }) } diff --git a/routes/schema.js b/routes/schema.js new file mode 100644 index 0000000..d8a82e6 --- /dev/null +++ b/routes/schema.js @@ -0,0 +1,103 @@ +module.exports = { + login: { + body: { + type: 'object', + required: ['login', 'password'], + properties: { + login: { type: 'string' }, + password: { type: 'string' } + }, + } + }, + logout: { + querystring: { + type: 'object', + required: ['login'], + properties: { + login: { type: 'string' } + } + } + }, + queryFlights: { + body: { + type: 'object', + required: ['fromAirport', 'fromDate', 'returnDate'], + properties: { + fromAirport: { type: 'string' }, + toAirport: { type: 'string' }, + fromDate: { type: 'string' }, + returnDate: { type: 'string' }, + oneWay: { type: 'boolean' } + } + } + }, + bookFlights: { + body: { + type: 'object', + required: ['userid', 'toFlightId'], + properties: { + userid: { type: 'string' }, + toFlightId: { type: 'string' }, + retFlightId: { type: 'string' }, + oneWay: { type: 'boolean' } + } + } + }, + cancelBooking: { + body: { + type: 'object', + required: ['userid', 'number'], + properties: { + userid: { type: 'string' }, + number: { type: 'string' } + } + } + }, + bookingsByUser: { + params: { + type: 'object', + required: ['user'], + properties: { + user: { type: 'string' } + } + } + }, + getCustomerById: { + params: { + type: 'object', + required: ['user'], + properties: { + user: { type: 'string' } + } + } + }, + putCustomerById: { + params: { + type: 'object', + required: ['user'], + properties: { + user: { type: 'string' } + } + }, + body: { + type: 'object', + properties: { + _id: { type: 'string' }, + password: { type: 'string' }, + phoneNumber: { type: 'string' }, + phoneNumberType: { type: 'string' }, + address: { + type: 'object', + properties: { + streetAddress1: { type: 'string' }, + streetAddress2: { type: 'string' }, + city: { type: 'string' }, + stateProvince: { type: 'string' }, + country: { type: 'string' }, + postalCode: { type: 'string' } + } + } + } + } + } +} \ No newline at end of file From c0babb59722be0dd56626404799c0c327c0e5b13 Mon Sep 17 00:00:00 2001 From: Igor Shmukler Date: Mon, 23 Apr 2018 13:36:42 +0300 Subject: [PATCH 5/5] work-in-progress app moved to fastify-cli/fastify-plugin architecture --- app.js | 182 +-------- dataaccess/mongo/index.js | 103 +---- fastify-plugin/index.js | 172 ++++++++ fastify-plugin/service.js | 147 +++++++ loader/loader.js | 4 +- package.json | 19 +- routes/index.js | 822 ++++++++++++++++---------------------- routes/schema.js | 3 + 8 files changed, 687 insertions(+), 765 deletions(-) create mode 100644 fastify-plugin/index.js create mode 100644 fastify-plugin/service.js diff --git a/app.js b/app.js index 1863e5c..1a5c34c 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,6 @@ /******************************************************************************* * Copyright (c) 2015 IBM Corp. +* Copyright (c) 2018 nearForm * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,178 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ +'use strict' -var Fastify = require('fastify') - , fs = require('fs') - , log4js = require('log4js') - , path = require('path'); -var settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')); +const path = require('path') -var logger = log4js.getLogger('app'); -logger.setLevel(settings.loggerLevel); - -// disable process.env.PORT for now as it cause problem on mesos slave -var port = (process.env.VMC_APP_PORT || process.env.VCAP_APP_PORT || settings.port); -var host = (process.env.VCAP_APP_HOST || 'localhost'); - -logger.info("host:port=="+host+":"+port); - -var authService; -var authServiceLocation = process.env.AUTH_SERVICE; -if (authServiceLocation) -{ - logger.info("Use authservice:"+authServiceLocation); - var authModule; - if (authServiceLocation.indexOf(":")>0) // This is to use micro services - authModule = "acmeairhttp"; - else - authModule= authServiceLocation; - - authService = new require('./'+authModule+'/index.js')(settings); - if (authService && "true"==process.env.enableHystrix) // wrap into command pattern - { - logger.info("Enabled Hystrix"); - authService = new require('./acmeaircmd/index.js')(authService, settings); - } -} - -var dbtype = process.env.dbtype || "mongo"; - -// Calculate the backend datastore type if run inside BLuemix or cloud foundry -if(process.env.VCAP_SERVICES){ - var env = JSON.parse(process.env.VCAP_SERVICES); - logger.info("env: %j",env); - var serviceKey = Object.keys(env)[0]; - if (serviceKey && serviceKey.indexOf('cloudant')>-1) - dbtype="cloudant"; - else if (serviceKey && serviceKey.indexOf('redis')>-1) - dbtype="redis"; -} -logger.info("db type=="+dbtype); - -var routes = new require('./routes/index.js')(dbtype, authService, settings); -var loader = new require('./loader/loader.js')(routes, settings); -var schema = require('./routes/schema.js'); - -// Setup fastify -var fastify = Fastify({ logger: settings.useDevLogger ? true : false }) // log every request to the console in development - -fastify.register(require('fastify-static'), { - root: path.join(__dirname, 'public') // set the static files location /public/img will be /img for users -}); - -fastify.register(require('fastify-cookie')) -fastify.register(require('fastify-formbody')) - -function router (fastify, opts, next) { - fastify.post('/login', { schema: schema.login }, login); - fastify.get('/login/logout', { schema: schema.logout }, logout); - fastify.post('/flights/queryflights', { schema: schema.queryFlights, beforeHandler: routes.checkForValidSessionCookie }, routes.queryflights); - fastify.post('/bookings/bookflights', { schema: schema.bookFlights, beforeHandler: routes.checkForValidSessionCookie }, routes.bookflights); - fastify.post('/bookings/cancelbooking', { schema: schema.cancelBooking, beforeHandler: routes.checkForValidSessionCookie }, routes.cancelBooking); - fastify.get('/bookings/byuser/:user', { schema: schema.bookingsByUser, beforeHandler: routes.checkForValidSessionCookie }, routes.bookingsByUser); - fastify.get('/customer/byid/:user', { schema: schema.getCustomerById, beforeHandler: routes.checkForValidSessionCookie }, routes.getCustomerById); - fastify.post('/customer/byid/:user', { schema: schema.putCustomerById, beforeHandler: routes.checkForValidSessionCookie }, routes.putCustomerById); - fastify.get('/config/runtime', {}, routes.getRuntimeInfo); - fastify.get('/config/dataServices', {}, routes.getDataServiceInfo); - fastify.get('/config/activeDataService', {}, routes.getActiveDataServiceInfo); - fastify.get('/config/countBookings', {}, routes.countBookings); - fastify.get('/config/countCustomers', {}, routes.countCustomer); - fastify.get('/config/countSessions', {}, routes.countCustomerSessions); - fastify.get('/config/countFlights', {}, routes.countFlights); - fastify.get('/config/countFlightSegments', {}, routes.countFlightSegments); - fastify.get('/config/countAirports', {}, routes.countAirports); - // fastify.get('/loaddb', startLoadDatabase); - fastify.get('/loader/load', {}, startLoadDatabase); - fastify.get('/loader/query', {}, loader.getNumConfiguredCustomers); - fastify.get('/checkstatus', {}, checkStatus); - - next() -} - -if (authService && authService.hystrixStream) - fastify.get('/rest/api/hystrix.stream', authService.hystrixStream); - - -// REGISTER OUR ROUTES so that all of routes will have prefix -fastify.register(router, { - prefix: settings.contextRoot -}) - - -// Only initialize DB after initialization of the authService is done -var initialized = false; -var serverStarted = false; - -if (authService && authService.initialize) -{ - authService.initialize(function(){ - initDB(); - }); -} -else - initDB(); - -function checkStatus(req, reply) { - reply.send("OK"); -} - -function login(req, reply) { - if (!initialized) { - logger.info("please wait for db connection initialized then trigger again."); - initDB(); - reply.code(403).send('Forbidden'); - } else { - routes.login(req, reply); - } -} - -function logout(req, reply){ - if (!initialized) - { - logger.info("please wait for db connection initialized then trigger again."); - initDB(); - reply.code(400).send('Bad request'); - }else - routes.logout(req, reply); -} - - -function startLoadDatabase(req, reply){ - if (!initialized) - { - logger.info("please wait for db connection initialized then trigger again."); - initDB(); - reply.code(400).send('Bad request'); - }else - loader.startLoadDatabase(req, reply); -} - -function initDB(){ - if (initialized ) return; - routes.initializeDatabaseConnections(function(error) { - if (error) { - logger.info('Error connecting to database - exiting process: '+ error); - // Do not stop the process for debug in container service - //process.exit(1); - } else { - initialized =true; - } - - logger.info("Initialized database connections"); - startServer(); - }); -} - - -function startServer() { - if (serverStarted) return; - serverStarted = true; - fastify.listen(port, function (err) { - if (err) { - logger.error("Error starting server " + err); - process.exit(1) - } - }); - logger.info("Fastify server listening on port " + port); +module.exports = async (fastify, opts) => { + fastify + .register(require('./fastify-plugin'), { prefix: '/rest/api' }) + .register(require('fastify-static'), { + root: path.join(__dirname, 'public'), + prefix: '/' + }) } diff --git a/dataaccess/mongo/index.js b/dataaccess/mongo/index.js index 446ee64..449394c 100644 --- a/dataaccess/mongo/index.js +++ b/dataaccess/mongo/index.js @@ -23,14 +23,14 @@ // findBy(collname, condition as json of field and value,function(err, docs)) // count(collname, condition as json of field and value, function(error, count)) -module.exports = function (settings) { +module.exports = function (dbclient) { var module = {}; - var mongodb = require('mongodb'); +// var mongodb = require('mongodb'); var log4js = require('log4js'); var logger = log4js.getLogger('dataaccess/mongo'); - logger.setLevel(settings.loggerLevel); +// logger.setLevel(settings.loggerLevel); module.dbNames = { customerName: "customer", @@ -41,100 +41,6 @@ module.exports = function (settings) { airportCodeMappingName:"airportCodeMapping" } - var dbclient = null; - - module.initializeDatabaseConnections = function(callback/*(error)*/) { - var mongo = null; - var mongoURI = null; - if(process.env.VCAP_SERVICES){ - var env = JSON.parse(process.env.VCAP_SERVICES); - logger.info("env: %j",env); - var serviceKey = Object.keys(env)[0]; - if (serviceKey) - { - mongo = env[serviceKey][0]['credentials']; - logger.info("mongo: %j",mongo); - } - } - - // The section is for docker integration using link - if (mongo ==null && process.env.MONGO_PORT!=null) { - logger.info(process.env.MONGO_PORT); - logger.info(process.env.MONGO_PORT_27017_TCP_ADDR); - logger.info(process.env.MONGO_PORT_27017_TCP_PORT); - mongo = { - "hostname": process.env.MONGO_PORT_27017_TCP_ADDR, - "port": process.env.MONGO_PORT_27017_TCP_PORT, - "username":"", - "password":"", - "name":"", - "db":"acmeair" - } - } - // Default to read from settings file - if (mongo==null) { - mongo = { - "hostname": settings.mongoHost, - "port": settings.mongoPort, - "username":"", - "password":"", - "name":"", - "db":"acmeair" - } - } - - var generate_mongo_url = function(obj){ - if (process.env.MONGO_URL) - { - logger.info("mongo: %j",process.env.MONGO_URL); - return process.env.MONGO_URL; - } - if (obj['uri']!=null) - { - return obj.uri; - } - if (obj['url']!=null) - { - return obj.url; - } - obj.hostname = (obj.hostname || 'localhost'); - obj.port = (obj.port || 27017); - obj.db = (obj.db || 'acmeair'); - - if(obj.username && obj.password){ - return "mongodb://" + obj.username + ":" + obj.password + "@" + obj.hostname + ":" + obj.port + "/" + obj.db; - } - else{ - return "mongodb://" + obj.hostname + ":" + obj.port + "/" + obj.db; - } - } - - var mongourl = generate_mongo_url(mongo); - - var c_opt = {server:{auto_reconnect:true,poolSize: settings.mongoConnectionPoolSize}}; - mongodb.connect(mongourl, c_opt, function(err, conn){ - if (err){ - callback(err); - }else { - dbclient=conn; - // Add ensureIndex here - dbclient.ensureIndex(module.dbNames.bookingName, {customerId:1} - , {background:true}, function(err, indexName) { - logger.info("ensureIndex:"+err+":"+indexName); - }); - dbclient.ensureIndex(module.dbNames.flightName, {flightSegmentId:1,scheduledDepartureTime:2} - , {background:true}, function(err, indexName) { - logger.info("ensureIndex:"+err+":"+indexName); - }); - dbclient.ensureIndex(module.dbNames.flightSegmentName, {originPort:1,destPort:2} - , {background:true}, function(err, indexName) { - logger.info("ensureIndex:"+err+":"+indexName); - }); - callback(null); - } - }); - } - module.insertOne = function (collectionname, doc, callback /* (error, insertedDocument) */) { dbclient.collection(collectionname,function(error, collection){ if (error){ @@ -147,7 +53,6 @@ module.exports = function (settings) { }); }; - module.findOne = function(collectionname, key, callback /* (error, doc) */) { dbclient.collection(collectionname, function(error, collection){ if (error){ @@ -231,6 +136,4 @@ module.exports = function (settings) { }; return module; - } - diff --git a/fastify-plugin/index.js b/fastify-plugin/index.js new file mode 100644 index 0000000..41ab58c --- /dev/null +++ b/fastify-plugin/index.js @@ -0,0 +1,172 @@ +'use strict' + +const fp = require('fastify-plugin') + +const fs = require('fs'), + log4js = require('log4js'), + settings = JSON.parse(fs.readFileSync('settings.json', 'utf8')), + schema = require('../routes/schema.js'), + Service = require('./service') + + +const logger = log4js.getLogger('app'); +logger.setLevel(settings.loggerLevel); + +// disable process.env.PORT for now as it cause problem on mesos slave +const port = (process.env.VMC_APP_PORT || process.env.VCAP_APP_PORT || settings.port); +const host = (process.env.VCAP_APP_HOST || 'localhost'); + +logger.info("host:port=="+host+":"+port); + +let authService, + authModule; +const authServiceLocation = process.env.AUTH_SERVICE; +if (authServiceLocation) { + logger.info("Use authservice:"+authServiceLocation); + if (authServiceLocation.indexOf(":")>0) // This is to use micro services + authModule = "acmeairhttp"; + else + authModule= authServiceLocation; + + authService = new require('./'+authModule+'/index.js')(settings); + if (authService && "true"==process.env.enableHystrix) // wrap into command pattern + { + logger.info("Enabled Hystrix"); + authService = new require('./acmeaircmd/index.js')(authService, settings); + } +} + +let dbtype = process.env.dbtype || "mongo"; + +// Calculate the backend datastore type if run inside BLuemix or cloud foundry +if (process.env.VCAP_SERVICES) { + var env = JSON.parse(process.env.VCAP_SERVICES); + logger.info("env: %j",env); + var serviceKey = Object.keys(env)[0]; + if (serviceKey && serviceKey.indexOf('cloudant')>-1) + dbtype="cloudant"; + else if (serviceKey && serviceKey.indexOf('redis')>-1) + dbtype="redis"; +} +logger.info("db type=="+dbtype); + +//let initialized = false + +/* + * This is the login plugin + * A plugin is a self contained component, so we need to made some operations: + * - check the configuration (fastify-env) + * - connect to mongodb (fastify-mongodb) + * - configure JWT library (fastify-jwt) + * - build business login objects + * - define the HTTP API + */ +module.exports = async function (fastify, opts) { + // This is a plugin registration inside a plugin + // fastify-env checks and coerces `opts` and save the result in `fastify.config` + // See https://github.com/fastify/fastify-env + fastify.register(require('fastify-env'), { + schema: { + type: 'object', + required: [ 'dbtype' ], + properties: { + dbtype: { type: 'string', default: 'mongo' }, + VMC_APP_PORT: {type: 'string'}, + VCAP_APP_PORT: {type: 'string'}, + VCAP_APP_HOST: {type: 'string', default: 'localhost'}, + AUTH_SERVICE: {type: 'string'} + } + }, + data: opts + }) + + // This registration is made in order to wait the previous one + // `avvio` (https://github.com/mcollina/avvio), the startup manager of `fastify`, + // registers this plugin only when the previous plugin has been registered + fastify.register(async function (fastify, opts) { + logger.info('config:', fastify.config) + // We need a connection database: + // `fastify-mongodb` makes this connection and store the database instance into `fastify.mongo.db` + // See https://github.com/fastify/fastify-mongodb + const dbtype = fastify.config['dbtype'] + if ('mongo' === dbtype) { + fastify.register(require('fastify-mongodb'), { + url: `mongodb://${settings.mongoHost}:${settings.mongoPort}/acmeair` + }) + // Add another business logic object to `fastify` instance + // Again, `fastify-plugin` is used in order to access to `fastify.service` from outside + fastify.register(fp(async function (fastify, opts) { + const service = new Service(fastify.mongo, require('../dataaccess/mongo/')(fastify.mongo)) + fastify.decorate('service', service) + })) + } else if ('redis' === dbtype) { + // XXX - this is wrong + fastify.register(require('fastify-redis'), { + host: `mongodb://${settings.mongoHost}:${settings.mongoPort}/acmeair`, + port: 0 + }) + // Add another business logic object to `fastify` instance + // Again, `fastify-plugin` is used in order to access to `fastify.service` from outside + fastify.register(fp(async function (fastify, opts) { + const service = new Service(fastify.redis) + fastify.decorate('service', service) + })) + } + + // Natively, `fastify` only accepts JSON, `fastify-formbody` will help us to + // process `Content-Type: application/x-www-form-urlencoded` + fastify.register(require('fastify-formbody')) + + fastify.register(require('fastify-cookie'), err => { + if (err) throw err + }) + + // Finally we're registering out routes + fastify.register(registerRoutes) + }) +} + +async function registerRoutes (fastify, opts) { + const { service } = fastify + const { ObjectId } = fastify.mongo + + const dataaccess = require('../dataaccess/mongo/')(fastify.mongo.db) + const loader = new require('../loader/loader.js')(dataaccess, settings) + const routes = new require('../routes/')(dataaccess, service, settings) + + fastify.post('/login', { schema: schema.login }, routes.login) + fastify.get('/login/logout', routes.logout) + fastify.get('/loader/load', {}, async (req, reply) => { + loader.startLoadDatabase(req, reply); + }); + fastify.get('/loader/query', {}, loader.getNumConfiguredCustomers); + fastify.get('/config/runtime', {}, routes.configRuntime); + fastify.get('/config/dataServices', {}, routes.configDataServices); + fastify.get('/config/activeDataService', {}, async (req, reply) => { + reply.send(dbtype); + }); + fastify.get('/config/countCustomers', {}, routes.countCustomers); + fastify.get('/config/countSessions', {}, routes.countSessions); + fastify.get('/config/countFlights', {}, routes.countFlights); + fastify.get('/config/countFlightSegments', {}, routes.countFlightSegments); + fastify.get('/config/countBookings', {}, routes.countBookings); + fastify.get('/config/countAirports', {}, routes.countAirports); + fastify.post('/flights/queryflights', + { schema: schema.queryFlights, beforeHandler: routes.checkForValidSessionCookie }, + routes.queryFlights); + fastify.post('/bookings/bookflights', + { schema: schema.bookFlights, beforeHandler: routes.checkForValidSessionCookie }, + routes.bookFlights); + fastify.get('/bookings/byuser/:user', + { schema: schema.bookingsByUser, beforeHandler: routes.checkForValidSessionCookie }, + routes.bookingsByUser); + fastify.post('/bookings/cancelbooking', + { schema: schema.cancelBooking, beforeHandler: routes.checkForValidSessionCookie }, + routes.cancelBooking); + fastify.get('/customer/byid/:user', + { schema: schema.getCustomerById, beforeHandler: routes.checkForValidSessionCookie }, + routes.getCustomerById); + fastify.post('/customer/byid/:user', + { schema: schema.putCustomerById, beforeHandler: routes.checkForValidSessionCookie }, + routes.putCustomerById); +} diff --git a/fastify-plugin/service.js b/fastify-plugin/service.js new file mode 100644 index 0000000..5988e7d --- /dev/null +++ b/fastify-plugin/service.js @@ -0,0 +1,147 @@ +/******************************************************************************* +* Copyright (c) 2018 nearForm +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*******************************************************************************/ +'use strict' + +const Boom = require('boom') +const DUPLICATE_KEY_ERROR_CODE = 11000 +const uuid = require('node-uuid') + +class Service { + constructor (dataAccess, provider) { + this.dataAccess = dataAccess + this.provider = provider + } + + async login (login, password) { + // const user = await this.userCollection.findOne({ _id: login, password: password }) + const user = await this.dataAccess.db.collection(this.provider.dbNames.customerName).findOne({ _id: login, password: password }) + if (!user) throw Boom.badData('Check your username') + + if (!user || user.password !== password) throw Boom.badData('Wrong credentials') + + try { + const sessiondid = await this.createSession(login) + return sessiondid + } + catch (error) { + throw Boom.badImplementation(); + } + } + + async logout (sessionid) { + await this.invalidateSession(sessionid); + } + + async createSession(customerId) { + if (this.authService){ + this.authService.createSession(customerId,callback); + return; + } + var now = new Date(); + var later = new Date(now.getTime() + 1000*60*60*24); + + var document = { "_id" : uuid.v4(), "customerid" : customerId, "lastAccessedTime" : now, "timeoutTime" : later }; + + try { + await this.dataAccess.db.collection(this.provider.dbNames.customerSessionName).insertOne(document) + return document._id + } + catch (error) { + console.log('error:', error) + throw Boom.badImplementation(); + } + } + + async invalidateSession(sessionid) { + if (this.authService){ + this.authService.invalidateSession(sessionid, callback); + return; + } + this.dataAccess.db.collection(this.provider.dbNames.customerSessionName).remove({'_id':sessionid}) + } + + async countItems(dbName) { + const count = await this.dataAccess.db.collection(dbName).count({}); + return count; + }; + + async validateSession(sessionId) { + if (this.authService){ + this.authService.validateSession(sessionId, callback); + return; + } + const now = new Date(); + try { + const session = await this.dataAccess.db.collection(this.provider.dbNames.customerSessionName).findOne({ _id: sessionId}) + if (now > session.timeoutTime) { + try { + await this.dataAccess.db.collection(this.provider.dbNames.customerSessionName).remove({'_id':sessionId}) + return null; + } + catch (error) { + console.log('error:', error) + } + } else { + return session.customerid + } + } + catch (error) { + console.log('error:', error) + } + } + + async findBy(dbName, condition) { + try { + const docs = await this.dataAccess.db.collection(dbName).find(condition).toArray() + return docs + } + catch (error) { + return null + } + } + + async insertOne(dbName, doc) { + try { + await this.dataAccess.db.collection(dbName).insert(doc, {safe: true}) + } + catch (error) { + // logger.error("insertOne hit error:"+error); + } + } + + async remove (dbName, condition) { + const numDocs = await this.dataAccess.db.collection(dbName).remove({_id: condition._id}, {safe: true}) + } + + async findOne(dbName, key) { + return await this.dataAccess.db.collection(dbName).findOne({_id: key}) + } + + async update(dbName, doc) { + try { + const numUpdates = await this.dataAccess.db.collection(dbName).update({_id: doc._id}, doc, {safe: true}) + // logger.debug(numUpdates); + return doc + } + catch (e) { + // logger.debug('error:', e) + console.log('error:', e) + throw e + } + } +} + +module.exports = Service diff --git a/loader/loader.js b/loader/loader.js index 15e60c9..804b7d5 100644 --- a/loader/loader.js +++ b/loader/loader.js @@ -14,7 +14,7 @@ * limitations under the License. *******************************************************************************/ -module.exports = function (loadUtil,settings) { +module.exports = function (loadUtil, settings) { var module = {}; var csv = require('csv'); @@ -114,6 +114,7 @@ module.exports = function (loadUtil,settings) { } function insertFlightSegment(flightSegment, callback) { + logger.debug('segment to insert = ' + JSON.stringify(flightSegment)); loadUtil.insertOne(loadUtil.dbNames.flightSegmentName, flightSegment, function(error, flightSegmentInserted) { logger.debug('flightSegment inserted = ' + JSON.stringify(flightSegmentInserted)); callback(); @@ -128,6 +129,7 @@ module.exports = function (loadUtil,settings) { } module.startLoadDatabase = function startLoadDatabase(req, reply) { + console.log('customers:', customers) if (customers.length>=1) { reply.send('Already loaded'); return; diff --git a/package.json b/package.json index bb66c4a..879978a 100644 --- a/package.json +++ b/package.json @@ -3,25 +3,34 @@ "version": "0.0.4", "private": true, "scripts": { - "start": "node app.js" + "start": "fastify start -p 9080 app.js" }, "dependencies": { "async": "0.2.10", "body-parser": "1.11.x", + "boom": "^5.2.0", "cassandra-driver": "2.0.x", "circuit-breaker": "0.0.4", "cookie-parser": "1.3.x", "csv": "0.2.4", - "fastify": "^0.41.0", - "fastify-cookie": "^1.2.0", - "fastify-formbody": "^1.2.3", - "fastify-static": "^0.6.0", + "fastify": "^1.2.1", + "fastify-cli": "^0.16.0", + "fastify-cookie": "^2.0.1", + "fastify-env": "^0.4.0", + "fastify-formbody": "^2.0.0", + "fastify-mongodb": "^0.6.0", + "fastify-plugin": "^1.0.0", + "fastify-redis": "^0.1.1", + "fastify-static": "^0.4.1", + "fastify-swagger": "^0.1.1", "log4js": "0.6.12", "method-override": "2.3.x", "mongodb": "2.0.x", "morgan": "1.5.x", "nano": "5.10.x", "node-uuid": "1.3.3", + "request": "^2.85.0", + "request-promise": "^4.2.2", "stats-lite": "1.0.3", "ttl-lru-cache": "0.0.2" } diff --git a/routes/index.js b/routes/index.js index dcd77a3..302a8a0 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,517 +1,365 @@ -/******************************************************************************* -* Copyright (c) 2015 IBM Corp. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*******************************************************************************/ +const uuid = require('node-uuid') -module.exports = function (dbtype, authService, settings) { - var module = {}; - var uuid = require('node-uuid'); - var log4js = require('log4js'); - var flightCache = require('ttl-lru-cache')({maxLength:settings.flightDataCacheMaxSize}); - var flightSegmentCache = require('ttl-lru-cache')({maxLength:settings.flightDataCacheMaxSize}); - var flightDataCacheTTL = settings.flightDataCacheTTL == -1 ? null : settings.flightDataCacheTTL; - - var logger = log4js.getLogger('routes'); - logger.setLevel(settings.loggerLevel); +module.exports = function (dataAccess, fastifyService, settings, authService) { + const dataaccess = dataAccess, + service = fastifyService, + flightCache = require('ttl-lru-cache')({maxLength:settings.flightDataCacheMaxSize}); + flightDataCacheTTL = settings.flightDataCacheTTL == -1 ? null : settings.flightDataCacheTTL, + flightSegmentCache = require('ttl-lru-cache')({maxLength:settings.flightDataCacheMaxSize}); - var daModuleName = "../dataaccess/"+dbtype+"/index.js"; - logger.info("Use dataaccess:"+daModuleName); - var dataaccess = new require(daModuleName)(settings); - - module.dbNames = dataaccess.dbNames - - module.initializeDatabaseConnections = function(callback/*(error)*/) { - dataaccess.initializeDatabaseConnections(callback) - } + module.login = async (req, reply) => { + const login = req.body.login, + password = req.body.password; + reply.setCookie('sessionid', ''); + const response = await service.login(login, password); + reply.setCookie('sessionid', response); + reply.send('logged in'); + } - module.insertOne = function (collectionname, doc, callback /* (error, insertedDocument) */) { - dataaccess.insertOne(collectionname, doc, callback) - }; + module.logout = async (req, reply) => { + const sessionid = req.cookies.sessionid; + const response = await service.logout(sessionid); + reply.setCookie('sessionid', ''); + reply.send('logged out'); + } - module.checkForValidSessionCookie = function(req, reply, done) { - logger.debug('checkForValidCookie'); - var sessionid = req.cookies.sessionid; - if (sessionid) { - sessiondid = sessionid.trim(); - } - if (!sessionid || sessionid == '') { - logger.debug('checkForValidCookie - no sessionid cookie so returning 403'); - reply.code(403).send('Forbidden'); - return; - } - - validateSession(sessionid, function(err, customerid) { - if (err) { - logger.debug('checkForValidCookie - system error validating session so returning 500'); - reply.code(500).send('Internal Server Eror'); - return; - } - - if (customerid) { - logger.debug('checkForValidCookie - good session so allowing done route handler to be called'); - req.acmeair_login_user = customerid; - done(); - return; - } - else { - logger.debug('checkForValidCookie - bad session so returning 403'); - reply.code(403).send('Forbidden'); - return; - } - }); + module.configRuntime = async (req, reply) => { + let runtimeInfo = []; + runtimeInfo.push({"name":"Runtime","description":"NodeJS"}); + const versions = process.versions; + for (var key in versions) { + runtimeInfo.push({"name":key,"description":versions[key]}); } + reply.send(JSON.stringify(runtimeInfo)); + } - module.login = function(req, reply) { - logger.debug('logging in user'); - var login = req.body.login; - var password = req.body.password; - - reply.setCookie('sessionid', ''); - - // replace eventually with call to business logic to validate customer - validateCustomer(login, password, function(err, customerValid) { - if (err) { - reply.code(500).send(err); // TODO: do I really need this or is there a cleaner way?? - return; - } - - if (!customerValid) { - reply.code(403).send('Forbidden'); - } - else { - createSession(login, function(error, sessionid) { - if (error) { - logger.info(error); - reply.code(500).send(error); - return; - } - reply.setCookie('sessionid', sessionid); - reply.send('logged in'); - }); - } - }); - }; + module.configDataServices = async (req, reply) => { + const dataServices = [{"name":"cassandra","description":"Apache Cassandra NoSQL DB"}, + {"name":"cloudant","description":"IBM Distributed DBaaS"}, + {"name":"mongo","description":"MongoDB NoSQL DB"}]; + reply.send(JSON.stringify(dataServices)); + } - module.logout = function(req, reply) { - logger.debug('logging out user'); - - var sessionid = req.cookies.sessionid; - invalidateSession(sessionid, function(err) { - reply.setCookie('sessionid', ''); - reply.send('logged out'); - }); - }; + module.countCustomers = async (req, reply) => { + try { + const count = await service.countItems(dataaccess.dbNames.customerName); + reply.send(count.toString()); + } + catch (e) { + reply.send("-1"); + } + } - module.queryflights = function(req, reply) { - logger.debug('querying flights'); - - var fromAirport = req.body.fromAirport; - var toAirport = req.body.toAirport; - var fromDateWeb = new Date(req.body.fromDate); - var fromDate = new Date(fromDateWeb.getFullYear(), fromDateWeb.getMonth(), fromDateWeb.getDate()); // convert date to local timezone - var oneWay = (req.body.oneWay == 'true'); - var returnDateWeb = new Date(req.body.returnDate); - var returnDate; - if (!oneWay) { - returnDate = new Date(returnDateWeb.getFullYear(), returnDateWeb.getMonth(), returnDateWeb.getDate()); // convert date to local timezone - } - - getFlightByAirportsAndDepartureDate(fromAirport, toAirport, fromDate, function (error, flightSegmentOutbound, flightsOutbound) { - logger.debug('flightsOutbound = ' + flightsOutbound); - if (flightsOutbound) { - for (ii = 0; ii < flightsOutbound.length; ii++) { - flightsOutbound[ii].flightSegment = flightSegmentOutbound; - } - } - else { - flightsOutbound = []; - } - if (!oneWay) { - getFlightByAirportsAndDepartureDate(toAirport, fromAirport, returnDate, function (error, flightSegmentReturn, flightsReturn) { - logger.debug('flightsReturn = ' + JSON.stringify(flightsReturn)); - if (flightsReturn) { - for (ii = 0; ii < flightsReturn.length; ii++) { - flightsReturn[ii].flightSegment = flightSegmentReturn; - } - } - else { - flightsReturn = []; - } - var options = {"tripFlights": - [ - {"numPages":1,"flightsOptions": flightsOutbound,"currentPage":0,"hasMoreOptions":false,"pageSize":10}, - {"numPages":1,"flightsOptions": flightsReturn,"currentPage":0,"hasMoreOptions":false,"pageSize":10} - ], "tripLegs":2}; - reply.send(options); - }); - } - else { - var options = {"tripFlights": - [ - {"numPages":1,"flightsOptions": flightsOutbound,"currentPage":0,"hasMoreOptions":false,"pageSize":10} - ], "tripLegs":1}; - reply.send(options); - } - }); - }; - - module.bookflights = function(req, reply) { - logger.debug('booking flights'); - - var userid = req.body.userid; - var toFlight = req.body.toFlightId; - var retFlight = req.body.retFlightId; - var oneWay = (req.body.oneWayFlight == 'true'); - - logger.debug("toFlight:"+toFlight+",retFlight:"+retFlight); - - bookFlight(toFlight, userid, function (error, toBookingId) { - if (!oneWay) { - bookFlight(retFlight, userid, function (error, retBookingId) { - var bookingInfo = {"oneWay":false,"returnBookingId":retBookingId,"departBookingId":toBookingId}; - reply - .header('Cache-Control', 'no-cache') - .send(bookingInfo); - }); - } - else { - var bookingInfo = {"oneWay":true,"departBookingId":toBookingId}; - reply - .header('Cache-Control', 'no-cache') - .send(bookingInfo); - } - }); - }; + module.countSessions = async (req, reply) => { + try { + const count = await service.countItems(dataaccess.dbNames.customerSessionName); + reply.send(count.toString()); + } + catch (e) { + reply.send("-1"); + } + } - module.cancelBooking = function(req, reply) { - logger.debug('canceling booking'); - - var number = req.body.number; - var userid = req.body.userid; - - cancelBooking(number, userid, function (error) { - if (error) { - reply.send({'status':'error'}); - } - else { - reply.send({'status':'success'}); - } - }); - }; + module.countFlights = async (req, reply) => { + try { + const count = await service.countItems(dataaccess.dbNames.flightName); + reply.send(count.toString()); + } + catch (e) { + reply.send("-1"); + } + } - module.bookingsByUser = function(req, reply) { - logger.debug('listing booked flights by user ' + req.params.user); - - getBookingsByUser(req.params.user, function(err, bookings) { - if (err) { - reply.code(500).send('Internal Server Error'); - } - reply.send(bookings); - }); - }; + module.countFlightSegments = async (req, reply) => { + try { + const count = await service.countItems(dataaccess.dbNames.flightSegmentName); + reply.send(count.toString()); + } + catch (e) { + reply.send("-1"); + } + } - module.getCustomerById = function(req, reply) { - logger.debug('getting customer by user ' + req.params.user); - - getCustomer(req.params.user, function(err, customer) { - if (err) { - reply.code(500).send('Internal Server Error'); - } - reply.send(customer); - }); - }; + module.countBookings = async (req, reply) => { + try { + const count = await service.countItems(dataaccess.dbNames.bookingName); + reply.send(count.toString()); + } + catch (e) { + reply.send("-1"); + } + } - module.putCustomerById = function(req, reply) { - logger.debug('putting customer by user ' + req.params.user); - - updateCustomer(req.params.user, req.body, function(err, customer) { - if (err) { - reply.code(500).send('Internal Server Error'); - } - reply.send(customer); - }); - }; + module.countAirports = async (req, reply) => { + try { + const count = await service.countItems(dataaccess.dbNames.airportCodeMappingName) + reply.send(count.toString()); + } + catch (e) { + reply.send("-1"); + } + } - module.toGMTString = function(req, reply) { - logger.info('******* running eyecatcher function'); - var now = new Date().toGMTString(); - reply.send(now); - }; - - module.getRuntimeInfo = function(req, reply) { - var runtimeInfo = []; - runtimeInfo.push({"name":"Runtime","description":"NodeJS"}); - var versions = process.versions; - for (var key in versions) { - runtimeInfo.push({"name":key,"description":versions[key]}); - } - // res.contentType('application/json'); - reply.send(JSON.stringify(runtimeInfo)); - }; - - module.getDataServiceInfo = function(req, reply) { - var dataServices = [{"name":"cassandra","description":"Apache Cassandra NoSQL DB"}, - {"name":"cloudant","description":"IBM Distributed DBaaS"}, - {"name":"mongo","description":"MongoDB NoSQL DB"}]; - reply.send(JSON.stringify(dataServices)); - }; - - module.getActiveDataServiceInfo = function (req, reply) { - reply.send(dbtype); - }; - - module.countBookings = function(req, reply) { - countItems(module.dbNames.bookingName, function (error, count) { - if (error) { - reply.send("-1"); - } else { - reply.send(count.toString()); - } - }); - }; - - module.countCustomer = function(req, reply) { - countItems(module.dbNames.customerName, function (error, count) { - if (error){ - reply.send("-1"); - } else { - reply.send(count.toString()); - } - }); - }; - - module.countCustomerSessions = function(req, reply) { - countItems(module.dbNames.customerSessionName, function (error, count) { - if (error){ - reply.send("-1"); - } else { - reply.send(count.toString()); - } - }); - }; - - module.countFlights = function(req, reply) { - countItems(module.dbNames.flightName, function (error, count) { - if (error) { - reply.send("-1"); - } else { - reply.send(count.toString()); - } - }); - }; - - module.countFlightSegments = function(req, reply) { - countItems(module.dbNames.flightSegmentName, function (error, count) { - if (error){ - reply.send("-1"); - } else { - reply.send(count.toString()); - } - }); - }; - - module.countAirports = function(req, reply) { - countItems(module.dbNames.airportCodeMappingName, function (error, count) { - if (error) { - reply.send("-1"); - } else { - reply.send(count.toString()); - } - }); - }; - - function countItems(dbName, callback /*(error, count)*/) { - console.log("Calling count on " + dbName); - dataaccess.count(dbName, {}, function(error, count) { - console.log("Output for "+dbName+" is "+count); - if (error) callback(error, null); - else { - callback(null,count); - } - }); - }; + module.checkForValidSessionCookie = async (req, reply, done) => { + let sessionid = req.cookies.sessionid; + if (sessionid) { + sessionid = sessionid.trim(); + } + if (!sessionid || sessionid == '') { + reply.code(403).send('Forbidden'); + return; + } + try { + const customerid = await service.validateSession(sessionid) + if (customerid) { + req.acmeair_login_user = customerid; + done(); + return; + } else { + reply.code(403).send('Forbidden'); + return; + } + } + catch (error) { + reply.code(500).send('Internal Server Eror'); + return; + } + } - function validateCustomer(username, password, callback /* (error, boolean validCustomer) */) { - dataaccess.findOne(module.dbNames.customerName, username, function(error, customer){ - if (error) { - callback (error, null); - } else { - if (customer) { - callback(null, customer.password == password); - } else { - callback(null, false) - } - } - }); - }; + module.queryFlights = async (req, reply) => { - function createSession(customerId, callback /* (error, sessionId) */) { - if (authService){ - authService.createSession(customerId,callback); - return; - } - var now = new Date(); - var later = new Date(now.getTime() + 1000*60*60*24); - - var document = { "_id" : uuid.v4(), "customerid" : customerId, "lastAccessedTime" : now, "timeoutTime" : later }; + const getFlightByAirportsAndDepartureDate = async function (fromAirport, toAirport, flightDate) { +// logger.info("getFlightByAirportsAndDepartureDate " + fromAirport + " " + toAirport + " " + flightDate); + + try { + const flightsegment = await getFlightSegmentByOriginPortAndDestPort(fromAirport, toAirport) +// logger.debug("flightsegment = " + JSON.stringify(flightsegment)); + if (!flightsegment) { + return {flightsegment: null, flights: null} + } + const date = new Date(flightDate.getFullYear(), flightDate.getMonth(), flightDate.getDate(),0,0,0,0); + + var cacheKey = flightsegment._id + "-" + date.getTime(); + if (settings.useFlightDataRelatedCaching) { + var flights = flightCache.get(cacheKey); + if (flights) { +// logger.debug("cache hit - flight search, key = " + cacheKey) + return {flightsegment: flightsegment, flights: (flights == "NULL" ? null : flights)} + } +// logger.debug("cache miss - flight search, key = " + cacheKey + " flightCache size = " + flightCache.size()) + } + const searchCriteria = {flightSegmentId: flightsegment._id, scheduledDepartureTime: date}; + console.log('looking for flights') + try { + const docs = await service.findBy(dataaccess.dbNames.flightName, searchCriteria); + ("after cache miss - key = " + cacheKey + ", docs = " + JSON.stringify(docs)); + + const docsEmpty = !docs || docs.length === 0; + + if (settings.useFlightDataRelatedCaching) { + const cacheValue = (docsEmpty ? "NULL" : docs); + ("about to populate the cache with flights key = " + cacheKey + " with value of " + JSON.stringify(cacheValue)); + flightCache.set(cacheKey, cacheValue, flightDataCacheTTL); + ("after cache populate with key = " + cacheKey + ", flightCacheSize = " + flightCache.size()) + } + return {flightsegment: flightsegment, flights: docs} + } + catch (err) { +// logger.error("hit error:"+err); + throw err + } + } + catch (error) { +// logger.error("Hit error:"+error); + throw error; + } + } - dataaccess.insertOne(module.dbNames.customerSessionName, document, function (error, doc){ - if (error) callback (error, null) - else callback(error, document._id); - }); - } + const getFlightSegmentByOriginPortAndDestPort = async function (fromAirport, toAirport, callback /* error, flightsegment */) { +// logger.info('getFlightSegmentByOriginPortAndDestPort') + let segment; + + if (settings.useFlightDataRelatedCaching) { + segment = flightSegmentCache.get(fromAirport+toAirport); +// logger.info('segment:', segment) + if (segment) { + ("cache hit - flightsegment search, key = " + fromAirport+toAirport); + return segment === "NULL" ? null : segment; + } + ("cache miss - flightsegment search, key = " + fromAirport+toAirport + ", flightSegmentCache size = " + flightSegmentCache.size()); + } + console.log('looking for segments') + try { + const docs = await service.findBy(dataaccess.dbNames.flightSegmentName, {originPort: fromAirport, destPort: toAirport}) + segment = docs[0]; + if (segment === undefined) { + segment = null; + } + if (settings.useFlightDataRelatedCaching) { + ("about to populate the cache with flightsegment key = " + fromAirport+toAirport + " with value of " + JSON.stringify(segment)); + flightSegmentCache.set(fromAirport+toAirport, (segment == null ? "NULL" : segment), flightDataCacheTTL); + ("after cache populate with key = " + fromAirport+toAirport + ", flightSegmentCacheSize = " + flightSegmentCache.size()) + } + return segment + } + catch (error) { + throw error + } + } + +// logger.info('querying flights'); - function validateSession(sessionId, callback /* (error, userid) */) { - if (authService){ - authService.validateSession(sessionId,callback); - return; - } - var now = new Date(); - - dataaccess.findOne(module.dbNames.customerSessionName, sessionId, function(err, session) { - if (err) callback (err, null); - else{ - if (now > session.timeoutTime) { - daraaccess.remove(module.dbNames.customerSessionName,{'_id':sessionId}, function(error) { - if (error) callback (error, null); - else callback(null, null); - }); - } - else - callback(null, session.customerid); - } - }); - } + const fromAirport = req.body.fromAirport, + toAirport = req.body.toAirport, + fromDateWeb = new Date(req.body.fromDate), + fromDate = new Date(fromDateWeb.getFullYear(), fromDateWeb.getMonth(), fromDateWeb.getDate()), // convert date to local timezone + oneWay = (req.body.oneWay == 'true'), + returnDateWeb = new Date(req.body.returnDate); + let returnDate; + if (!oneWay) { + returnDate = new Date(returnDateWeb.getFullYear(), returnDateWeb.getMonth(), returnDateWeb.getDate()); // convert date to local timezone + } + try { + const res = await getFlightByAirportsAndDepartureDate(fromAirport, toAirport, fromDate) + const flightSegmentOutbound = res.flightsegment + let flightsOutbound = res.flights +// logger.info('flightsOutbound = ' + flightsOutbound); + if (flightsOutbound) { + for (let i = 0; i < flightsOutbound.length; i++) { + flightsOutbound[i].flightSegment = flightSegmentOutbound; + } + } else { + flightsOutbound = []; + } + if (!oneWay) { + const result = await getFlightByAirportsAndDepartureDate(toAirport, fromAirport, returnDate) + const flightSegmentReturn = result.flightsegment; + let flightsReturn = result.flights; +// logger.info('flightsReturn = ' + JSON.stringify(flightsReturn)); + if (flightsReturn) { + for (let i = 0; i < flightsReturn.length; i++) { + flightsReturn[i].flightSegment = flightSegmentReturn; + } + } else { + flightsReturn = []; + } + const options = {"tripFlights": + [ + {"numPages":1,"flightsOptions": flightsOutbound,"currentPage":0,"hasMoreOptions":false,"pageSize":10}, + {"numPages":1,"flightsOptions": flightsReturn,"currentPage":0,"hasMoreOptions":false,"pageSize":10} + ], "tripLegs":2}; + reply.send(options); + } else { + const options = {"tripFlights": + [ + {"numPages":1,"flightsOptions": flightsOutbound,"currentPage":0,"hasMoreOptions":false,"pageSize":10} + ], "tripLegs":1}; + reply.send(options); + } + } + catch (e) { + console.log('error:', e) + } + } - function getCustomer(username, callback /* (error, Customer) */) { - dataaccess.findOne(module.dbNames.customerName, username, callback); + module.bookFlights = async (req, reply) => { + // logger.debug('booking flights'); + + const userid = req.body.userid, + toFlight = req.body.toFlightId, + retFlight = req.body.retFlightId, + oneWay = (req.body.oneWayFlight == 'true'); + + // logger.debug("toFlight:"+toFlight+",retFlight:"+retFlight); + const toBookingId = await bookFlight(toFlight, userid); + let bookingInfo; + if (!oneWay) { + const retBookingId = await bookFlight(retFlight, userid); + bookingInfo = {"oneWay":false,"returnBookingId":retBookingId,"departBookingId":toBookingId}; + } else { + bookingInfo = {"oneWay":true,"departBookingId":toBookingId}; } + reply + .header('Cache-Control', 'no-cache') + .send(bookingInfo); + } - function updateCustomer(login, customer, callback /* (error, Customer) */) { - dataaccess.update(module.dbNames.customerName, customer,callback) - } + const bookFlight = async (flightId, userid) => { + const now = new Date(), + docId = uuid.v4(), + document = { "_id" : docId, "customerId" : userid, "flightId" : flightId, "dateOfBooking" : now }; + try { + await service.insertOne(dataaccess.dbNames.bookingName, document) + return docId + } + catch (e) { + console.log('error:', e) + return null + } + } - function getBookingsByUser(username, callback /* (error, Bookings) */) { - dataaccess.findBy(module.dbNames.bookingName, {'customerId':username},callback) - } + module.bookingsByUser = async (req, reply) => { + // logger.debug('listing booked flights by user ' + req.params.user); + try { + const bookings = await getBookingsByUser(req.params.user) + reply.send(bookings); + } + catch (err) { + reply.code(500).send('Internal Server Error'); + } + } - function invalidateSession(sessionid, callback /* error */) { - if (authService){ - authService.invalidateSession(sessionid,callback); - return; - } - - dataaccess.remove(module.dbNames.customerSessionName,{'_id':sessionid},callback) - } + const getBookingsByUser = async (username) => { + return await service.findBy(dataaccess.dbNames.bookingName, {'customerId':username}) + } + module.cancelBooking = async (req, reply) => { + // logger.debug('canceling booking'); + const number = req.body.number, + userid = req.body.userid; + try { + await cancelBooking(number, userid) + reply.send({'status':'success'}); + } + catch (error) { + reply.send({'status':'error'}); + } + } - function getFlightByAirportsAndDepartureDate(fromAirport, toAirport, flightDate, callback /* error, flightSegment, flights[] */) { - logger.debug("getFlightByAirportsAndDepartureDate " + fromAirport + " " + toAirport + " " + flightDate); - - getFlightSegmentByOriginPortAndDestPort(fromAirport, toAirport, function(error, flightsegment) { - if (error) { - logger.error("Hit error:"+error); - throw error; - } - - logger.debug("flightsegment = " + JSON.stringify(flightsegment)); - if (!flightsegment) { - callback(null, null, null); - return; - } - - var date = new Date(flightDate.getFullYear(), flightDate.getMonth(), flightDate.getDate(),0,0,0,0); - - var cacheKey = flightsegment._id + "-" + date.getTime(); - if (settings.useFlightDataRelatedCaching) { - var flights = flightCache.get(cacheKey); - if (flights) { - logger.debug("cache hit - flight search, key = " + cacheKey); - callback(null, flightsegment, (flights == "NULL" ? null : flights)); - return; - } - logger.debug("cache miss - flight search, key = " + cacheKey + " flightCache size = " + flightCache.size()); - } - var searchCriteria = {flightSegmentId: flightsegment._id, scheduledDepartureTime: date}; - dataaccess.findBy(module.dbNames.flightName, searchCriteria, function(err, docs) { - if (err) { - logger.error("hit error:"+err); - callback (err, null, null); - }else - { - ("after cache miss - key = " + cacheKey + ", docs = " + JSON.stringify(docs)); - - var docsEmpty = !docs || docs.length == 0; - - if (settings.useFlightDataRelatedCaching) { - var cacheValue = (docsEmpty ? "NULL" : docs); - ("about to populate the cache with flights key = " + cacheKey + " with value of " + JSON.stringify(cacheValue)); - flightCache.set(cacheKey, cacheValue, flightDataCacheTTL); - ("after cache populate with key = " + cacheKey + ", flightCacheSize = " + flightCache.size()) - } - callback(null, flightsegment, docs); - } - }); - }); - } + const cancelBooking = async (bookingid, userid) => { + return await service.remove(dataaccess.dbNames.bookingName, {'_id':bookingid, 'customerId':userid}) + } - function getFlightSegmentByOriginPortAndDestPort(fromAirport, toAirport, callback /* error, flightsegment */) { - var segment; - - if (settings.useFlightDataRelatedCaching) { - segment = flightSegmentCache.get(fromAirport+toAirport); - if (segment) { - ("cache hit - flightsegment search, key = " + fromAirport+toAirport); - callback(null, (segment == "NULL" ? null : segment)); - return; - } - ("cache miss - flightsegment search, key = " + fromAirport+toAirport + ", flightSegmentCache size = " + flightSegmentCache.size()); - } - dataaccess.findBy(module.dbNames.flightSegmentName,{originPort: fromAirport, destPort: toAirport},function(err, docs) { - if (err) callback (err, null); - else { - segment = docs[0]; - if (segment == undefined) { - segment = null; - } - if (settings.useFlightDataRelatedCaching) { - ("about to populate the cache with flightsegment key = " + fromAirport+toAirport + " with value of " + JSON.stringify(segment)); - flightSegmentCache.set(fromAirport+toAirport, (segment == null ? "NULL" : segment), flightDataCacheTTL); - ("after cache populate with key = " + fromAirport+toAirport + ", flightSegmentCacheSize = " + flightSegmentCache.size()) - } - callback(null, segment); - } - }); - } + module.getCustomerById = async (req, reply) => { + // logger.debug('getting customer by user ' + req.params.user); + try { + const customer = await getCustomer(req.params.user) + reply.send(customer); + } + catch (err) { + reply.code(500).send('Internal Server Error'); + } + } + const getCustomer = async (username) => { + const result = await service.findOne(dataaccess.dbNames.customerName, username); + return result; + } - function bookFlight(flightId, userid, callback /* (error, bookingId) */) { - - var now = new Date(); - var docId = uuid.v4(); - - var document = { "_id" : docId, "customerId" : userid, "flightId" : flightId, "dateOfBooking" : now }; - - dataaccess.insertOne(module.dbNames.bookingName,document,function(err){ - callback(err, docId); - }); - } + module.putCustomerById = async (req, reply) => { + // logger.debug('putting customer by user ' + req.params.user); + try { + const customer = await updateCustomer(req.params.user, req.body) + reply.send(customer); + } + catch (err) { + reply.code(500).send('Internal Server Error'); + } + } - function cancelBooking(bookingid, userid, callback /*(error)*/) { - dataaccess.remove(module.dbNames.bookingName,{'_id':bookingid, 'customerId':userid}, callback) - } + const updateCustomer = async (login, customer) => { + return await service.update(dataaccess.dbNames.customerName, customer) + } - return module; + return module; } - diff --git a/routes/schema.js b/routes/schema.js index d8a82e6..57119b0 100644 --- a/routes/schema.js +++ b/routes/schema.js @@ -1,3 +1,5 @@ +'use strict' + module.exports = { login: { body: { @@ -7,6 +9,7 @@ module.exports = { login: { type: 'string' }, password: { type: 'string' } }, + additionalProperties: false } }, logout: {