'use strict'
var fs = require('fs')
var ini = require('ini')
var path = require('path')
var dxl = require('@opendxl/dxl-client')
var Client = dxl.Client
var Config = dxl.Config
var DXL_CLIENT_CONFIG_FILE = 'dxlclient.config'
/**
* @classdesc Responsible for all communication with the
* Data Exchange Layer (DXL) fabric.
* @external DxlClient
* @see {@link https://opendxl.github.io/opendxl-client-javascript/jsdoc/Client.html}
*/
/**
* Service registration instances are used to register and expose services onto
* a DXL fabric.
* @external ServiceRegistrationInfo
* @see {@link https://opendxl.github.io/opendxl-client-javascript/jsdoc/ServiceRegistrationInfo.html}
*/
/**
* @classdesc Base class used for DXL applications.
* @param {String} configDir - The directory containing the application
* configuration files.
* @param {String} appConfigFileName - The name of the application-specific
* configuration file.
* @constructor
*/
function Application (configDir, appConfigFileName) {
/**
* The DXL client to use for communication with the fabric.
* @private
* @type {external.DxlClient}
* @name Application#_dxlClient
*/
this._dxlClient = null
/**
* The directory containing the application configuration files.
* @private
* @type {String}
* @name Application#_configDir
*/
this._configDir = configDir
/**
* Full path to the file used to configure the DXL client.
* @private
* @type {String}
* @name Application#_dxlClientConfigPath
*/
this._dxlClientConfigPath = path.join(configDir, DXL_CLIENT_CONFIG_FILE)
/**
* Full path to the application-specifie configuration file.
* @private
* @type {String}
* @name Application#_appConfigPath
*/
this._appConfigPath = path.join(configDir, appConfigFileName)
/**
* Whether or not the application is currently running.
* @private
* @type {boolean}
* @name Application#_running
*/
this._running = false
/**
* Loads the configuration settings from the application-specific
* configuration file
* @private
*/
this._loadConfiguration = function () {
var configData
try {
configData = fs.readFileSync(this._appConfigPath, 'utf-8')
} catch (err) {
throw new Error('Unable to read configuration file: ' + err.message)
}
var parsedConfig
try {
parsedConfig = ini.parse(configData)
} catch (err) {
throw new Error('Unable to parse config file: ' + err.message)
}
this.onLoadConfiguration(parsedConfig)
}
/**
* Attempts to connect to the DXL fabric.
* @private
* @param {Function} [callback=null] - Callback function which should be
* invoked after the client has been connected.
*/
this._dxlConnect = function (callback) {
var that = this
var config = Config.createDxlConfigFromFile(this._dxlClientConfigPath)
this._dxlClient = new Client(config)
this._dxlClient.connect(function () {
that.onRegisterEventHandlers()
that.onRegisterServices()
that.onDxlConnect()
if (callback) {
callback()
}
})
}
}
/**
* Invoked after the client associated with the application has connected
* to the DXL fabric.
*/
Application.prototype.onDxlConnect = function () {}
/**
* Invoked after the application-specific configuration has been loaded
* @param {Object} config - The application-specific configuration, as an
* object parsed from the application-configuration file. For example, the
* configuration file could have the following content on disk:
*
* ```ini
* [General]
* requestPayload = ping
* ```
*
* The application could then reference the `requestPayload` setting from the
* `config` object as follows:
*
* ```js
* var payload = config.General.requestPayload
* ```
*/
Application.prototype.onLoadConfiguration = function (config) {}
/**
* Invoked when event handlers should be registered with the application.
*/
Application.prototype.onRegisterEventHandlers = function () {}
/**
* Invoked when services should be registered with the application.
*/
Application.prototype.onRegisterServices = function () {}
/**
* Invoked when the application has started running.
*/
Application.prototype.onRun = function () {}
/**
* Registers the specified service with the fabric.
* @param {external:ServiceRegistrationInfo} service - The service to register
* with the fabric
* @param {Function} [callback=null] - An optional callback that will be
* invoked when the registration attempt is complete. If an error occurs
* during the registration attempt, the first parameter supplied to the
* callback contains an {@link Error} with failure details.
*/
Application.prototype.registerServiceAsync = function (service, callback) {
this._dxlClient.registerServiceAsync(service, callback)
}
/**
* Runs the application.
* @param {Function} [callback=null] - An optional callback that will be
* invoked after the application has started running. The callback would be
* invoked after the DXL client has been connected to the fabric and calls to
* register services have been made.
*/
Application.prototype.run = function (callback) {
if (this._running) {
throw new Error('The application is already running')
}
this._running = true
this.onRun()
this._loadConfiguration()
this._dxlConnect(callback)
}
/**
* Destroys the application (disconnects from fabric, frees resources, etc.)
* @param {Function} [callback=null] - An optional callback that will be
* invoked after the application has been destroyed.
*/
Application.prototype.destroy = function (callback) {
if (this._dxlClient) {
this._dxlClient.destroy(callback)
}
}
module.exports = Application