js/base/runtime.js
// NPM IMPORTS
import assert from 'assert'
import { fromJS } from 'immutable'
import os from 'os'
// COMMON IMPORTS
import T from 'devapt-core-common/dist/js/utils/types'
import {SOURCE_LOCAL_FILE} from 'devapt-core-common/dist/js/datas/providers/json_provider'
import Context from 'devapt-core-common/dist/js/base/context'
import RuntimeBase from 'devapt-core-common/dist/js/base/runtime_base'
import topology_registry from 'devapt-core-common/dist/js/topology/registry/index'
import {register_runtime} from 'devapt-core-common/dist/js/base/runtime'
// SERVER IMPORTS
import Transaction from './transaction'
import Security from './security'
import * as exec from '../runtime/index'
/**
* Contextual constant for this file logs.
* @private
* @type {string}
*/
const context = 'server/base/runtime'
/**
* Console logger class path file.
* @type {string}
*/
const logger_console_file = 'devapt-core-common/dist/js/loggers/logger_console'
/**
* Default runtime settings.
* @type {object}
*/
const default_settings = {
'is_master':false,
'name': null,
'master':{
'name': null,
'host':'localhost',
'port':5000
},
'settings_provider': {
'source':SOURCE_LOCAL_FILE,
'relative_path':'apps/world.json'
}
}
/**
* @file Runtime class - main library interface.
*
* @author Luc BORIES
*
* @license Apache-2.0
*/
class Runtime extends RuntimeBase
{
/**
* Create a Runtime instance.
*
* @returns {nothing}
*/
constructor()
{
super(context)
// SET DEFAULT ATTRIBUTES VALUES
/**
* Class test flag.
* @type {boolean}
*/
this.is_server_runtime = true
/**
* Is master node flag.
* @type {boolean}
*/
this.is_master = false
/**
* Unique node id.
* @type {string}
*/
this.uid = os.hostname() + '_' + process.pid
/**
* Runtime settings.
* @private
* @type {Immutable.Map}
*/
this.$settings = undefined
/**
* Runtime node.
* @type {Node}
*/
this.node = null
/**
* Plugins factory instance.
* @type {PluginsFactory}
*/
this.plugins_factory = undefined
/**
* Runtime context instance.
* @type {Context}
*/
this.context = new Context(this)
/**
* Security manager instance.
* @type {SecurityManager}
*/
this.security_mgr = new Security(this, context, { 'logger_manager':this.get_logger_manager() } )
/**
* Topology state registry.
* @private
* @type {TopologyRegistry}
*/
this._state_store = topology_registry
/**
* Topology state registry.
* @type {TopologyRegistry}
*/
this.topology_registry = topology_registry
/**
* Topology world definition instance.
* @type {TopologyDefineWorld}
*/
this.defined_world_topology = undefined
/**
* Topology world deployment instance.
* @type {TopologyDeploymentWorld}
*/
this.deployed_local_topology= undefined
/**
* Servers using socketio.
* @type {object}
*/
this.socketio_servers = {}
this.info('Runtime is created')
}
/**
* Get runtime context.
*
* @returns {Context}
*/
get_context()
{
return this.context
}
/**
* Get runtime node.
*
* @returns {Node}
*/
get_node()
{
return this.node
}
/**
* Get runtime unique identifier.
*
* @returns {string}
*/
get_uid()
{
return this.uid
}
/**
* Get topology runtime singleton.
*
* @returns {object}
*/
get_registry()
{
return this.topology_registry
}
/**
* Get defined topology runtime singleton.
*
* @returns {TopologyDefineWorld} - defined world topology.
*/
get_defined_topology()
{
return this.defined_world_topology
}
/**
* Get deployed topology runtime singleton.
*
* @returns {TopologyDeployLocalNode} - deployed local node topology.
*/
get_deployed_topology()
{
return this.deployed_local_topology
}
/**
* Load runtime settings.
*
* @param {object} arg_settings - runtime settings.
*
* @returns {object} promise
*/
load(arg_settings)
{
const self = this
// MERGE DEFAULT AND RUNTIME SETTINGS
default_settings.runtime = this
arg_settings.runtime = this
this.$settings = fromJS( Object.assign(default_settings, arg_settings) )
// console.log(context + ':load:runtime.$settings', this.$settings)
// SET DEFAULT LOGGER
const trace_stages_enabled = this.$settings.getIn(['trace', 'stages', 'enabled'], false)
let console_logger_index = undefined
let console_logger_uid = undefined
if ( trace_stages_enabled )
{
const LoggerConsole = require(logger_console_file).default
// console.log(context + ':load:add console logger')
const console_settings = {
enabled:true
}
const logger = new LoggerConsole(true, console_settings)
console_logger_uid = logger.uid
this._logger_manager.loggers.push(logger)
console_logger_index = this._logger_manager.loggers.length - 1
// console.log(context + ':load:add console logger index=' + console_logger_index)
this.enable_trace()
}
// TRACES ARE ACTIVE IF ENABLED
this.separate_level_1()
this.enter_group('load')
this.is_master = this.get_setting('is_master', false)
// console.log(context + ':load:is_master', this.is_master, this.get_settings_js())
const stage0 = new exec.RuntimeStage0Executable(this._logger_manager)
const stage1 = new exec.RuntimeStage1Executable(this._logger_manager)
const stage2 = new exec.RuntimeStage2Executable(this._logger_manager)
const stage3 = new exec.RuntimeStage3Executable(this._logger_manager)
const execs = [stage0, stage1, stage2, stage3]
const tx = new Transaction('runtime', 'startup', 'loading', { runtime:this, logger_manager:this._logger_manager }, execs, Transaction.SEQUENCE)
// console.log(context + ':load:before tx new')
tx.prepare({runtime:this, logger_manager:this._logger_manager})
// console.log(context + ':load:after tx prepare')
const tx_promise = tx.execute(null)
// console.log(context + ':load:after tx execute')
if (console_logger_index >= 0)
{
// console.log(context + ':load:remove runtime loading console logger')
tx_promise.then(
() => {
if (self.get_logger_manager().loggers.length > console_logger_index && self.get_logger_manager().loggers[console_logger_index].get_uid() == console_logger_uid)
{
console.log(context + ':load:remove console logger at ' + console_logger_index)
self.get_logger_manager().loggers.splice(console_logger_index, 1)
}
}
)
}
this.leave_group('load')
this.separate_level_1()
return tx_promise
}
/**
* Get security object.
* @returns {Security}
*/
security()
{
assert( T.isObject(this.security_mgr) && this.security_mgr.is_security, context + ':bad security object')
return this.security_mgr
}
/**
* Get plugins factory object.
* @returns {PluginsFactory}
*/
get_plugins_factory()
{
assert( T.isObject(this.plugins_factory) && this.plugins_factory.is_plugins_factory, context + ':bad plugins factory object')
return this.plugins_factory
}
/**
* Register and configure a socketio server.
*
* @param {string} arg_server_name - bound server name.
* @param {object} arg_socketio - socketio server.
*
* @returns {nothing}
*/
add_socketio(arg_server_name, arg_socketio)
{
const self = this
assert( T.isString(arg_server_name), context + ':add_socketio:bad server name')
assert( T.isObject(arg_socketio) && arg_socketio.emit && arg_socketio.on, context + ':add_socketio:bad socketio server')
self.socketio_servers[arg_server_name] = arg_socketio
arg_socketio.on('connection',
function (socket)
{
console.info(context + ':add_socketio:new connection on /')
// ROOT
socket.on('disconnect',
function()
{
console.info(context + ':add_socketio:new disconnection on /')
self.on_socketio_disconnect()
}
)
self.on_socketio_connect(arg_socketio, socket)
}
)
}
/**
* On socketio server connect event.
* @param {object} arg_socketio - socketio server.
* @param {object} arg_socket - client socket.
* @returns {nothing}
*/
on_socketio_connect(arg_socketio, arg_socket)
{
assert( T.isObject(arg_socketio) && arg_socketio.emit && arg_socketio.on, context + ':on_socketio_connect:bad socketio server')
assert( T.isObject(arg_socket) && arg_socket.emit && arg_socket.on, context + ':on_socketio_connect:bad socketio socket client')
console.info(context + ':on_socketio_connect:socket connected')
arg_socket.emit('welcome on /', { from: 'server runtime' })
}
/**
* On socketio server disconnect event.
* @returns {nothing}
*/
on_socketio_disconnect()
{
console.info(context + ':on_socketio_disconnect:socket disconnected')
}
}
/**
* Runtime singleton instance.
* @private
* @type {Runtime}
*/
const runtime_singleton = new Runtime()
register_runtime(runtime_singleton)
/**
* Runtime singleton instance.
* @type {Runtime}
*/
export default runtime_singleton