hyperflow
Version:
A javascript state flow and mutation management toolkit & library for developing universal app.
886 lines (825 loc) • 40.9 kB
JavaScript
/**
* Copyright 2015-present Tuan Le.
*
* Licensed under the MIT License.
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://opensource.org/licenses/mit-license.html
*
* 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.
*
*------------------------------------------------------------------------
*
* @module DomainFactory
* @description - A domain factory.
*
* @author Tuan Le (tuan.t.lei@gmail.com)
*
* @flow
*/
; // eslint-disable-line
import CommonElement from '../elements/common-element';
/* load EventStreamComposite */
import EventStreamComposite from './composites/event-stream-composite';
/* load Composer */
import Composer from '../composer';
const Hf = CommonElement();
/* factory Ids */
import {
DOMAIN_FACTORY_CODE,
SERVICE_FACTORY_CODE,
STORE_FACTORY_CODE,
INTERFACE_FACTORY_CODE
} from './factory-code';
/* slow mode buffer timings */
const SLOW_MODE_BUFFER_TIME_SPAN_IN_MS = 500;
const SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS = 500;
/* time waiting for factory setup/teardown to complete */
const DEFAULT_SETUP_WAIT_TIME_IN_MS = 10000;
const DEFAULT_TEARDOWN_WAIT_TIME_IN_MS = 10000;
export default Composer({
composites: [
EventStreamComposite
],
state: {
name: {
value: `unnamed`,
required: true
},
fId: {
computable: {
contexts: [
`name`
],
compute () {
return `${DOMAIN_FACTORY_CODE}-${this.name}`;
}
}
}
},
DomainFactory () {
/* ----- Private Variables ------------- */
/* flag indicates start method has called */
let _started = false;
/* domain interface and store */
let _intf;
let _store;
/* services */
let _services = [];
/* child and peer domains */
let _childDomains = [];
let _peerDomains = [];
/* ----- Public Functions -------------- */
/**
* @description - Initialize interface, store, and child domains to this domain.
*
* @method $init
* @return void
*/
this.$init = function () {
Hf.log(`warn0`, `DomainFactory.$init - Method is not implemented by default.`);
};
/**
* @description - Setup domain event stream.
*
* @method setup
* @param {function} done
* @return void
*/
this.setup = function (done) { // eslint-disable-line
if (Hf.DEVELOPMENT) {
if (!Hf.isFunction(done)) {
Hf.log(`error`, `DomainFactory.setup - Input done function is invalid.`);
}
}
done();
};
/**
* @description - Teardown domain event stream.
*
* @method teardown
* @param {function} done
* @return void
*/
this.teardown = function (done) { // eslint-disable-line
if (Hf.DEVELOPMENT) {
if (!Hf.isFunction(done)) {
Hf.log(`error`, `DomainFactory.teardown - Input done function is invalid.`);
}
}
done();
};
/**
* @description - Check if domain has started.
*
* @method hasStarted
* @return {boolean}
*/
this.hasStarted = function () {
return _started;
};
/**
* @description - Get domain interface.
*
* @method getInterface
* @return {object}
*/
this.getInterface = function () {
const domain = this;
if (Hf.DEVELOPMENT) {
if (!Hf.isObject(_intf)) {
Hf.log(`warn0`, `DomainFactory.getInterface - Domain:${domain.name} is not registered with an interface.`);
}
}
return _intf;
};
/**
* @description - Get domain store.
*
* @method getStore
* @return {object}
*/
this.getStore = function () {
const domain = this;
if (Hf.DEVELOPMENT) {
if (!Hf.isObject(_store)) {
Hf.log(`warn0`, `DomainFactory.getStore - Domain:${domain.name} is not registered with a store.`);
}
}
return _store;
};
/**
* @description - Get domain services.
*
* @method getServices
* @param {array} serviceNames
* @return {array}
*/
this.getServices = function (...serviceNames) {
let services = [];
if (Hf.isNonEmptyArray(_services)) {
if (Hf.isNonEmptyArray(serviceNames)) {
if (Hf.DEVELOPMENT) {
if (!serviceNames.every((name) => Hf.isString(name))) {
Hf.log(`error`, `DomainFactory.getServices - Input service name is invalid.`);
} else if (!serviceNames.every((name) => _services.hasOwnProperty(name))) {
Hf.log(`error`, `DomainFactory.getServices - Service is not found.`);
}
}
services = services.concat(Hf.collect(...serviceNames).from(_services));
} else {
services = _services;
}
}
return services;
};
/**
* @description - Get domain children.
*
* @method getChildDomains
* @param {array} domainNames
* @return {array}
*/
this.getChildDomains = function (...domainNames) {
let childDomains = [];
if (Hf.isNonEmptyArray(_childDomains)) {
if (Hf.isNonEmptyArray(domainNames)) {
if (Hf.DEVELOPMENT) {
if (!domainNames.every((name) => Hf.isString(name))) {
Hf.log(`error`, `DomainFactory.getChildDomains - Input domain name is invalid.`);
} else if (!domainNames.every((name) => _childDomains.hasOwnProperty(name))) {
Hf.log(`error`, `DomainFactory.getChildDomains - Domain is not found.`);
}
}
childDomains = childDomains.concat(Hf.collect(...domainNames).from(_childDomains));
} else {
childDomains = _childDomains;
}
}
return childDomains;
};
/**
* @description - Get domain peers.
*
* @method getPeerDomains
* @param {array} domainNames
* @return {array}
*/
this.getPeerDomains = function (...domainNames) {
let peerDomains = [];
if (Hf.isNonEmptyArray(_peerDomains)) {
if (Hf.isNonEmptyArray(domainNames)) {
if (Hf.DEVELOPMENT) {
if (!domainNames.every((name) => Hf.isString(name))) {
Hf.log(`error`, `DomainFactory.getPeerDomains - Input domain name is invalid.`);
} else if (!domainNames.every((name) => _peerDomains.hasOwnProperty(name))) {
Hf.log(`error`, `DomainFactory.getPeerDomains - Domain is not found.`);
}
}
peerDomains = peerDomains.concat(Hf.collect(...domainNames).from(_peerDomains));
} else {
peerDomains = _peerDomains;
}
}
return peerDomains;
};
/**
* @description - Register child domains, store and interface.
*
* @method register
* @param {object} definition - Domain registration definition for interface (required), child domains, and store.
* @return {object}
*/
this.register = function (definition) {
const domain = this;
// TODO: Throw error if called outside of $init.
if (Hf.DEVELOPMENT) {
if (!Hf.isSchema({
intf: `object|undefined`,
store: `object|undefined`,
services: `array|undefined`,
peerDomains: `array|undefined`,
childDomains: `array|undefined`
}).of(definition)) {
Hf.log(`error`, `DomainFactory.register - Input definition is invalid.`);
}
}
const {
intf,
store,
services,
peerDomains,
childDomains
} = definition;
if (Hf.isObject(intf)) {
if (Hf.DEVELOPMENT) {
if (!Hf.isSchema({
fId: `string`,
name: `string`,
composedOf: `function`,
reflectStateOf: `function`,
setup: `function`,
teardown: `function`,
observe: `function`,
activateIncomingStream: `function`,
activateOutgoingStream: `function`,
deactivateIncomingStream: `function`,
deactivateOutgoingStream: `function`,
getInterfaceComposites: `function`
}).of(intf) || intf.fId.substr(0, INTERFACE_FACTORY_CODE.length) !== INTERFACE_FACTORY_CODE) {
Hf.log(`error`, `DomainFactory.register - Input interface is invalid.`);
} else if (Hf.isObject(_intf)) {
Hf.log(`warn1`, `DomainFactory.register - Domain:${domain.name} already registered interface:${_intf.name}.`);
}
}
_intf = intf;
Hf.log(`info1`, `Domain:${domain.name} registered interface:${_intf.name}.`);
}
if (Hf.isObject(store)) {
if (Hf.DEVELOPMENT) {
if (!Hf.isSchema({
fId: `string`,
name: `string`,
setup: `function`,
teardown: `function`,
observe: `function`,
activateIncomingStream: `function`,
activateOutgoingStream: `function`,
deactivateIncomingStream: `function`,
deactivateOutgoingStream: `function`
}).of(store) || store.fId.substr(0, STORE_FACTORY_CODE.length) !== STORE_FACTORY_CODE) {
Hf.log(`error`, `DomainFactory.register - Input store is invalid.`);
} else if (!Hf.isObject(_intf)) {
Hf.log(`error`, `DomainFactory.register - Cannot register store:${store.name} without first register an interface.`);
} else if (Hf.isObject(_store)) {
Hf.log(`warn1`, `DomainFactory.register - Domain:${domain.name} already registered store:${_store.name}.`);
}
}
_store = store;
Hf.log(`info1`, `Domain:${domain.name} registered store:${_store.name}.`);
}
if (Hf.isObject(_store) && Hf.isObject(_intf)) {
/* interface is now stateful and reflecting its state with a store */
_intf.reflectStateOf(_store);
}
if (Hf.isArray(services)) {
if (Hf.DEVELOPMENT) {
if (!services.every((service) => {
return Hf.isSchema({
fId: `string`,
name: `string`,
getChildServices: `function`,
setup: `function`,
teardown: `function`,
observe: `function`,
activateIncomingStream: `function`,
activateOutgoingStream: `function`,
deactivateIncomingStream: `function`,
deactivateOutgoingStream: `function`
}).of(service) && service.fId.substr(0, SERVICE_FACTORY_CODE.length) === SERVICE_FACTORY_CODE;
})) {
Hf.log(`error`, `DomainFactory.register - Input services are invalid.`);
}
}
_services = _services.concat(services.filter((service) => {
if (_services.includes(service.name)) {
Hf.log(`warn1`, `DomainFactory.register - Domain:${domain.name} already registered service:${service.name}.`);
return false;
}
Hf.log(`info1`, `Domain:${domain.name} registered service:${service.name}.`);
return true;
}));
}
if (Hf.isArray(childDomains)) {
if (Hf.DEVELOPMENT) {
if (!childDomains.every((childDomain) => {
return Hf.isSchema({
fId: `string`,
name: `string`,
start: `function`,
stop: `function`,
observe: `function`,
getInterface: `function`
}).of(childDomain) && childDomain.fId.substr(0, DOMAIN_FACTORY_CODE.length) === DOMAIN_FACTORY_CODE;
})) {
Hf.log(`error`, `DomainFactory.register - Input child domains are invalid.`);
}
}
_childDomains = _childDomains.concat(childDomains.filter((childDomain) => {
if (domain.name === childDomain.name) {
Hf.log(`warn1`, `DomainFactory.register - Cannot register domain:${childDomain.name} as a child of itself.`);
return false;
} else if (_peerDomains.includes(childDomain.name)) {
Hf.log(`warn1`, `DomainFactory.register - Child domain:${childDomain.name} is already registered as a peer.`);
return false;
}
Hf.log(`info1`, `Domain:${domain.name} registered child domain:${childDomain.name}.`);
return true;
}));
if (Hf.isObject(_intf)) {
_intf.composedOf(
..._childDomains.map((childDomain) => childDomain.getInterface()).filter((compositeIntf) => Hf.isObject(compositeIntf))
);
}
}
if (Hf.isArray(peerDomains)) {
if (Hf.DEVELOPMENT) {
if (!peerDomains.every((peerDomain) => {
return Hf.isSchema({
fId: `string`,
name: `string`,
start: `function`,
stop: `function`,
observe: `function`,
getInterface: `function`
}).of(peerDomain) && peerDomain.fId.substr(0, DOMAIN_FACTORY_CODE.length) === DOMAIN_FACTORY_CODE;
})) {
Hf.log(`error`, `DomainFactory.register - Input peer domains are invalid.`);
}
}
_peerDomains = _peerDomains.concat(peerDomains.filter((peerDomain) => {
if (domain.name === peerDomain.name) {
Hf.log(`warn1`, `DomainFactory.register - Cannot register domain:${peerDomain.name} as a peer of itself.`);
return false;
} else if (_childDomains.includes(peerDomain.name)) {
Hf.log(`warn1`, `DomainFactory.register - Peer domain:${peerDomain.name} is already registered as a child.`);
return false;
}
Hf.log(`info1`, `Domain:${domain.name} registered peer domain:${peerDomain.name}.`);
return true;
}));
}
return domain;
};
/**
* @description - Start domain.
*
* @method start
* @param {function} done
* @param {object} option
* @return void
*/
this.start = function (done, option = {
enableSlowRunMode: false,
waitTime: DEFAULT_SETUP_WAIT_TIME_IN_MS
}) {
const domain = this;
const {
enableSlowRunMode,
waitTime,
timeout
} = Hf.fallback({
enableSlowRunMode: false,
waitTime: DEFAULT_SETUP_WAIT_TIME_IN_MS
}).of(option);
if (Hf.DEVELOPMENT) {
if (!Hf.isFunction(done)) {
Hf.log(`error`, `DomainFactory.start - Input done function is invalid.`);
}
}
if (!_started) {
const domainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Domain:${domain.name} is taking longer than ${waitTime}ms to setup.`);
if (Hf.isFunction(timeout)) {
timeout(domain.name);
}
}, waitTime);
Hf.log(`info1`, `Starting domain:${domain.name}...`);
/* setup event stream with domain observing interface */
if (Hf.isObject(_intf)) {
domain.observe(_intf);
}
/* setup event stream observation duplex between domain and store */
if (Hf.isObject(_store)) {
domain.observe(_store);
_store.observe(domain);
/* setup event stream with interface observing store */
if (Hf.isObject(_intf)) {
_intf.observe(_store);
}
}
/* setup event stream observation duplex between domain and servies and children of services */
if (Hf.isNonEmptyArray(_services)) {
domain.observe(..._services);
_services.forEach((service) => {
const childServices = service.getChildServices();
service.observe(domain);
if (Hf.isNonEmptyArray(childServices)) {
service.observe(...childServices);
childServices.forEach((childService) => childService.observe(service));
}
});
}
/* setup event stream observation duplex between domain and children */
if (Hf.isNonEmptyArray(_childDomains)) {
domain.observe(..._childDomains);
_childDomains.forEach((childDomain) => childDomain.observe(domain));
}
/* setup event stream observation duplex between domain and peers */
if (Hf.isNonEmptyArray(_peerDomains)) {
let index = 0;
while (index < _peerDomains.length - 1) {
_peerDomains[index].observe(..._peerDomains.slice(index + 1));
_peerDomains.slice(index + 1).forEach((peerDomain) => peerDomain.observe(_peerDomains[index])); // eslint-disable-line
index++;
}
domain.observe(..._peerDomains);
_peerDomains.forEach((peerDomain) => peerDomain.observe(domain));
}
domain.setup(() => {
/* first activate parent domain incoming stream */
domain.activateIncomingStream({
forceBufferingOnAllIncomingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
/* then startup child domains... */
if (Hf.isNonEmptyArray(_childDomains)) {
_childDomains.forEach((childDomain) => {
const childDomainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Child domain:${childDomain.name} is taking longer than ${waitTime}ms to start.`);
if (Hf.isFunction(timeout)) {
timeout(childDomain.name);
}
}, waitTime);
childDomain.start(() => clearTimeout(childDomainTimeoutId), option);
});
}
/* then startup peer domains... */
if (Hf.isNonEmptyArray(_peerDomains)) {
_peerDomains.forEach((peerDomain) => {
const peerDomainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Peer domain:${peerDomain.name} is taking longer than ${waitTime}ms to start.`);
if (Hf.isFunction(timeout)) {
timeout(peerDomain.name);
}
}, waitTime);
peerDomain.start(() => clearTimeout(peerDomainTimeoutId), option);
});
}
/* then activate parent to child interfaces... */
if (Hf.isObject(_intf)) {
/* helper function to activate all child interfaces event stream */
const deepInterfaceActivateStream = (intf) => {
if (Hf.isObject(intf)) {
const intfTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Interface:${intf.name} is taking longer than ${waitTime}ms to setup.`);
if (Hf.isFunction(timeout)) {
timeout(intf.name);
}
}, waitTime);
intf.setup(() => {
intf.activateIncomingStream({
forceBufferingOnAllIncomingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
intf.getInterfaceComposites().forEach((compositeIntf) => deepInterfaceActivateStream(compositeIntf));
intf.activateOutgoingStream({
forceBufferingOnAllOutgoingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
Hf.log(`info1`, `Activated interface:${intf.name}.`);
clearTimeout(intfTimeoutId);
});
} else {
Hf.log(`warn0`, `DomainFactory.start - DomainFactory.start.deepInterfaceActivateStream - Input interface is invalid.`);
}
};
deepInterfaceActivateStream(_intf);
} else {
Hf.log(`warn0`, `DomainFactory.start - Domain:${domain.name} is not registered with an interface.`);
}
/* then activate store... */
if (Hf.isObject(_store)) {
const storeTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Store:${_store.name} is taking longer than ${waitTime}ms to setup.`);
if (Hf.isFunction(timeout)) {
timeout(_store.name);
}
}, waitTime);
_store.setup(() => {
_store.activateIncomingStream({
forceBufferingOnAllIncomingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
_store.activateOutgoingStream({
forceBufferingOnAllOutgoingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
Hf.log(`info1`, `Activated store:${_store.name}.`);
clearTimeout(storeTimeoutId);
});
}
/* then activate services... */
if (Hf.isNonEmptyArray(_services)) {
/* helper function to activate all child service event stream */
const deepChildServiceActivateStream = (childService) => {
if (Hf.isObject(childService)) {
const childServiceTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Service:${childService.name} is taking longer than ${waitTime}ms to setup.`);
if (Hf.isFunction(timeout)) {
timeout(childService.name);
}
}, waitTime);
childService.setup(() => {
childService.activateIncomingStream({
forceBufferingOnAllIncomingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
childService.getChildServices().forEach((_childService) => deepChildServiceActivateStream(_childService));
childService.activateOutgoingStream({
forceBufferingOnAllOutgoingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
Hf.log(`info1`, `Activated service:${childService.name}.`);
clearTimeout(childServiceTimeoutId);
});
} else {
Hf.log(`warn0`, `DomainFactory.start - DomainFactory.start.deepChildServiceActivateStream - Input interface is invalid.`);
}
};
_services.forEach((service) => {
const serviceTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.start - Service:${service.name} is taking longer than ${waitTime}ms to setup.`);
if (Hf.isFunction(timeout)) {
timeout(service.name);
}
}, waitTime);
deepChildServiceActivateStream(service);
service.setup(() => {
service.activateIncomingStream({
forceBufferingOnAllIncomingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
service.activateOutgoingStream({
forceBufferingOnAllOutgoingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
Hf.log(`info1`, `Activated service:${service.name}.`);
clearTimeout(serviceTimeoutId);
});
});
}
/* then finally activate domain... */
domain.activateOutgoingStream({
forceBufferingOnAllOutgoingStreams: enableSlowRunMode,
bufferTimeSpan: SLOW_MODE_BUFFER_TIME_SPAN_IN_MS,
bufferTimeShift: SLOW_MODE_BUFFER_TIME_SHIFT_IN_MS
});
_started = true;
Hf.log(`info1`, `Domain:${domain.name} has started.`);
clearTimeout(domainTimeoutId);
done();
});
} else { // eslint-disable-line
domain.restart(done, option);
}
};
/**
* @description - Stop domain.
*
* @method stop
* @param {function} done
* @param {object} option
* @return void
*/
this.stop = function (done, option = {
resetStoreState: true,
resetAllServiceStates: true,
waitTime: DEFAULT_TEARDOWN_WAIT_TIME_IN_MS
}) {
const {
resetStoreState,
resetAllServiceStates,
waitTime,
timeout
} = Hf.fallback({
resetStoreState: true,
resetAllServiceStates: true,
waitTime: DEFAULT_TEARDOWN_WAIT_TIME_IN_MS
}).of(option);
const domain = this;
if (Hf.DEVELOPMENT) {
if (!Hf.isFunction(done)) {
Hf.log(`error`, `DomainFactory.stop - DomainFactory.stop - Input done function is invalid.`);
}
}
if (_started) {
const domainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.stop - Domain:${domain.name} is taking longer than ${waitTime}ms to teardown.`);
if (Hf.isFunction(timeout)) {
timeout(domain.name);
}
}, waitTime);
Hf.log(`info1`, `Stopping domain:${domain.name}...`);
domain.teardown(() => {
/* first stop child domains... */
if (Hf.isNonEmptyArray(_childDomains)) {
_childDomains.forEach((childDomain) => {
const childDomainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `Child domain:${childDomain.name} is taking longer than ${waitTime}ms to stop.`);
if (Hf.isFunction(timeout)) {
timeout(childDomain.name);
}
}, waitTime);
childDomain.stop(() => clearTimeout(childDomainTimeoutId), option);
});
}
/* then peer domains... */
if (Hf.isNonEmptyArray(_peerDomains)) {
_peerDomains.forEach((peerDomain) => {
const peerDomainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `Peer domain:${peerDomain.name} is taking longer than ${waitTime}ms to stop.`);
if (Hf.isFunction(timeout)) {
timeout(peerDomain.name);
}
}, waitTime);
peerDomain.stop(() => clearTimeout(peerDomainTimeoutId), option);
});
}
/* then stop child to parent interfaces... */
if (Hf.isObject(_intf)) {
/* helper function to deactivate all child interfaces event stream */
const deepInterfaceDeactivateStream = (intf) => {
if (Hf.isObject(intf)) {
const intfTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.stop - Interface:${intf.name} is taking longer than ${waitTime}ms to teardown.`);
if (Hf.isFunction(timeout)) {
timeout(intf.name);
}
}, waitTime);
intf.teardown(() => {
intf.getInterfaceComposites().forEach((compositeIntf) => deepInterfaceDeactivateStream(compositeIntf));
// TODO: compositeIntf does not or should not have incoming event stream activated.
intf.deactivateIncomingStream();
intf.deactivateOutgoingStream();
// TODO: Un-reflect state from store?
Hf.log(`info1`, `Deactivated interface:${intf.name}.`);
clearTimeout(intfTimeoutId);
});
} else {
Hf.log(`warn0`, `DomainFactory.stop - DomainFactory.stop.deepInterfaceDeactivateStream - Input interface is invalid.`);
}
};
deepInterfaceDeactivateStream(_intf);
}
/* then store... */
if (Hf.isObject(_store)) {
const storeTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.stop - Store:${_store.name} is taking longer than ${waitTime}ms to teardown.`);
if (Hf.isFunction(timeout)) {
timeout(_store.name);
}
}, waitTime);
_store.teardown(() => {
_store.deactivateIncomingStream();
_store.deactivateOutgoingStream();
if (resetStoreState && Hf.isFunction(_store.reset)) {
/* reset store state */
_store.reset();
}
Hf.log(`info1`, `Deactivated store:${_store.name}.`);
clearTimeout(storeTimeoutId);
});
}
/* then services... */
if (Hf.isNonEmptyArray(_services)) {
/* helper function to deactivate all child services event stream */
const deepChildServiceDeactivateStream = (childService) => {
if (Hf.isObject(childService)) {
const childServiceTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.stop - Service:${childService.name} is taking longer than ${waitTime}ms to teardown.`);
if (Hf.isFunction(timeout)) {
timeout(childService.name);
}
}, waitTime);
childService.teardown(() => {
childService.getChildServices().forEach((_childService) => deepChildServiceDeactivateStream(_childService));
childService.deactivateIncomingStream();
childService.deactivateOutgoingStream();
Hf.log(`info1`, `Deactivated service:${childService.name}.`);
clearTimeout(childServiceTimeoutId);
});
} else {
Hf.log(`warn0`, `DomainFactory.stop - DomainFactory.stop.deepChildServiceDeactivateStream - Input service is invalid.`);
}
};
_services.forEach((service) => {
const serviceTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.stop - Service:${service.name} is taking longer than ${waitTime}ms to teardown.`);
if (Hf.isFunction(timeout)) {
timeout(service.name);
}
}, waitTime);
deepChildServiceDeactivateStream(service);
service.teardown(() => {
service.deactivateIncomingStream();
service.deactivateOutgoingStream();
if (resetAllServiceStates && Hf.isFunction(service.reset)) {
/* reset service state */
service.reset();
}
Hf.log(`info1`, `Deactivated service:${service.name}.`);
clearTimeout(serviceTimeoutId);
});
});
}
/* then finally parent domain. */
domain.deactivateIncomingStream();
domain.deactivateOutgoingStream();
_started = false;
Hf.log(`info1`, `Domain:${domain.name} has stopped.`);
clearTimeout(domainTimeoutId);
done();
});
}
};
/**
* @description - Restart domain.
*
* @method restart
* @param {function} done,
* @param {object} option,
* @return void
*/
this.restart = function (done, option = {
waitTime: DEFAULT_SETUP_WAIT_TIME_IN_MS
}) {
const domain = this;
const {
waitTime,
timeout
} = Hf.fallback({
waitTime: DEFAULT_SETUP_WAIT_TIME_IN_MS
}).of(option);
if (Hf.DEVELOPMENT) {
if (!Hf.isFunction(done)) {
Hf.log(`error`, `DomainFactory.restart - Input done function is invalid.`);
}
}
const domainTimeoutId = setTimeout(() => {
Hf.log(`warn1`, `DomainFactory.restart - Domain:${domain.name} is taking longer than ${waitTime} seconds to stop and restart.`);
if (Hf.isFunction(timeout)) {
timeout(domain.name);
}
}, waitTime);
domain.stop(() => {
clearTimeout(domainTimeoutId);
domain.start(done, option);
}, option);
};
}
});