js/executables/executable_route.js
// NPM IMPORTS
import assert from 'assert'
// COMMON IMPORTS
import T from 'devapt-core-common/dist/js/utils/types'
import Executable from 'devapt-core-common/dist/js/base/executable'
import {get_runtime} from 'devapt-core-common/dist/js/base/runtime'
// SERVER IMPORTS
/**
* Runtime instance.
* @private
* @type {RuntimeBase}
*/
const runtime = get_runtime()
/**
* Contextual constant for this file logs.
* @private
*/
const context = 'services/executables/executable_route'
/**
* @file Route registering base class.
* @author Luc BORIES
* @license Apache-2.0
*/
export default class ExecutableRoute extends Executable
{
/**
* Create a ExecutableRoute instance.
* @abstract
*/
constructor()
{
super(context, runtime.get_logger_manager())
/**
* Executable settings.
* @protected
* @type {object}
*/
this.store_config = undefined
/**
* Executable server.
* @protected
* @type {object}
*/
this.server = undefined
}
/**
* Prepare an execution with contextual informations.
* @override
*
* @param {object} arg_settings - execution settings.
*
* @returns {nothing}
*/
prepare(arg_settings)
{
// console.log(context + ':prepare:arg_settings', arg_settings)
assert( T.isObject(arg_settings), context + ':no given config')
this.store_config = arg_settings
assert(T.isObject(this.store_config), context + ':bad config object')
assert(T.isObject(this.store_config.server), context + ':bad server object')
assert(this.store_config.server.is_server, context + ':bad server instance')
this.server = this.store_config.server
}
/**
* Execution with contextual informations.
* @override
*
* @param {object} arg_data - Application instance.
*
* @returns {object} promise.
*/
execute(arg_data)
{
// console.log(context + ':execute:store_config', this.store_config)
// CHECK APPLICATION
assert(T.isObject(arg_data), context + ':bad application object')
assert(arg_data.is_topology_define_application, context + ':bad application instance')
const application = arg_data
this.info('Execute: add server route for ' + application.get_name())
// CHECK SERVER
const server_instance = this.server
assert(T.isString(server_instance.server_type), context + ':bad server_instance.server_type string')
assert(T.isObject(server_instance.server) || T.isFunction(server_instance.server), context + ':bad server_instance.server object or function')
// LOOP ON ROUTES
this.debug('this.store_config.routes', this.store_config.routes)
let routes_registering_promises = []
assert(T.isArray(this.store_config.routes), context + ':bad store_config.routes object')
const cfg_routes = this.store_config.routes
// PROBLEM WITH NODEJS 0.10
// for(let cfg_route of cfg_routes)
// {
for(let cfg_route_index = 0 ; cfg_route_index < cfg_routes.length ; cfg_route_index++)
{
// GET ROUTE CONFIG
let cfg_route = cfg_routes[cfg_route_index]
this.debug('loop on cfg_route', cfg_route)
assert(T.isObject(cfg_route), context + ':bad cfg_route object')
assert(T.isString(cfg_route.route), context + ':bad route string')
// GET APPLICATION URL
const app_url = T.isString(application.app_url) ? application.app_url : ''
this.debug('app_route', app_url)
// GET ROUTE IS GLOBAL (HAS FULL ROUTE INSIDE)
const route_is_global = (T.isBoolean(cfg_route.is_global) && cfg_route.is_global == true)
// GET APPLICATION ROUTE
let app_route = route_is_global ? cfg_route.route : app_url + cfg_route.route
app_route = (app_route[0] == '/' ? '' : '/') + app_route
cfg_route.full_route = app_route
// DEBUG
// console.log('route=%s, app_route=%s, cfg.route=%s, is_global=%s, cond=%s', route, app_route, cfg_route.route, cfg_route.is_global, (cfg_route.is_global && cfg_route.is_global == true))
// GET REGEXP
cfg_route.route_regexp = undefined
if ( app_route.indexOf('.*') > -1 || app_route.indexOf('$') > -1 || app_route.indexOf('^') > -1 )
{
cfg_route.route_regexp = new RegExp( app_route.replace('/', '\/') )
}
this.debug('route', cfg_route.full_route.toString())
this.debug('directory', cfg_route.directory)
const route_resistering_promise = this.process_route(server_instance, application, cfg_route, arg_data)
routes_registering_promises.push(route_resistering_promise)
this.info('registering route [' + app_route + '] for application [' + application.$name + ']')
}
return Promise.all(routes_registering_promises)
}
/**
* Process a route registering.
*
* @param {Server} arg_server - Server instance.
* @param {TopologyDefineApplication} arg_application - Application instance.
* @param {object} arg_cfg_route - plain object route configuration.
* @param {object} arg_data - plain object contextual datas.
*
* @returns {Promise} - Promise(boolean) with (true:success, false: failure).
*/
process_route(arg_server, arg_application, arg_cfg_route, arg_data)
{
// DEBUG
// console.log(arg_cfg_route, 'arg_cfg_route')
// GET ROUTE CALLBACK
const route_cb = this.get_route_cb(arg_application, arg_cfg_route, arg_data)
if (!route_cb)
{
console.error('bad route callback', context)
return Promise.reject(context + ':process_route:bad route callback')
}
// CHECK SERVER
if ( ! T.isObject(arg_server) || ! arg_server.is_server || ! arg_server.is_routable_server )
{
return Promise.reject(context + ':process_route:bad server type')
}
// ADD ROUTE HANDLER
try
{
arg_server.add_get_route(arg_cfg_route, route_cb)
return Promise.resolve(true)
}
catch(e)
{
console.error(e, context)
const cfg_route_str = JSON.stringify(arg_cfg_route)
return Promise.reject(context + ':process_route:' + e.toString() + ' for route config=[' + cfg_route_str + ']')
}
}
/**
* Callback for route handling.
* @abstract
*
* @param {TopologyDefineApplication} arg_application - Application instance.
* @param {object} arg_cfg_route - plain object route configuration.
* @param {object} arg_data - plain object contextual datas.
*
* @param {function} route handler.
*/
get_route_cb(/*arg_application, arg_cfg_route, arg_data*/)
{
assert(false, context + ':get_route_cb(cfg_route) should be implemented')
}
/**
* Callback for redirect route handling.
*
* @param {TopologyDefineApplication} arg_application - Application instance.
* @param {object} arg_cfg_route - plain object route configuration.
* @param {object} arg_data - plain object contextual datas.
*
* @param {function} route handler.
*/
get_route_redirect_cb(arg_application, arg_cfg_route/*, arg_data*/)
{
assert(T.isString(arg_cfg_route.redirect), context + ':bad redirect route string')
return (req, res/*, next*/) => {
const url = runtime.context.get_url_with_credentials(arg_cfg_route.redirect, req)
res.redirect(url)
}
}
}