@indra.ai/deva
Version:
Deva Core a Vedic-inspired Event Based Context Aware Feature, Zone, Action, and State Machine integrated Artificial Intelligence Framework
1,473 lines (1,313 loc) • 77.2 kB
JavaScript
"use strict";
// Copyright ©2025 Quinn A Michaels; All rights reserved.
// Legal Signature Required For Lawful Use.
// Distributed under VLA:44091450722329207445 LICENSE.md
import {EventEmitter} from 'node:events';
import {createHash,randomUUID} from 'crypto';
import lib from './lib/index.js';
import config from './config/index.js';
import pkg from './package.json' with {type:'json'};
class Deva {
constructor(opts) {
opts = opts || {}; // set opts to provided opts or an empty object.
this._core = pkg; // set the core from the package data.
this._id = opts.id || randomUUID(); // the unique id assigned to the agent at load
this._info = opts.info || false; // the deva information from the package file.
this._config = opts.config || {}; // local Config Object
this._agent = opts.agent || false; // Agent profile object
this._client = {}; // this will be set on init.
this._active = false; // the active/birth date.
this._indra = false; // inherited Indra features.
this._veda = false; // inherited Veda features.
this._license = false; // inherited License features.
this._data = false; // inherited Data features.
this._error = false; // inherited Error features.
this._log = false; // inherited Log features.
this._report = false; // inherited Report features.
this._vector = false; // inherited Vector features.
this._king = false; // inherited King features.
this._treasury = false; // inherited Vector features.
this._security = false; // inherited Security features.
this._guard = false; // inherited Guard features.
this._defense = false; // inherited Security features.
this._wall = false; // inherited Wall features.
this._proxy = false; // inherited Proxy features.
this._legal = false; // inherited Legal features.
this._authority = false; // inherited Justice features.
this._justice = false; // inherited Justice features.
this._support = false; // inherited Support features.
this._services = false; // inherited Service features.
this._systems = false; // inherited Systems features.
this._networks = false; // inherited Systems features.
this.events = opts.events || new EventEmitter({}); // Event Bus
this.lib = new lib({pkg}); // used for loading library functions
this.utils = opts.utils || {}; // parse functions inside the deva
this.devas = opts.devas || {}; // Devas which are loaded
this.vars = opts.vars || {}; // Variables object
this.listeners = opts.listeners || {}; // local Listeners
this.modules = opts.modules || {}; // 3rd Party Modules
this.func = opts.func || {}; // local Functions
this.methods = opts.methods || {}; // local Methods
this.maxListeners = opts.maxListenners || 0; // set the local maxListeners
// prevent overwriting existing functions and variables with same name
for (const opt in opts) {
if (!this[opt] || !this[`_${opt}`]) this[opt] = opts[opt];
}
this.cmdChr = config.cmdChr; // the trigger for local commands
this.askChr = config.askChr; // the trigger for ask other DEva features
this._inherit = config.inherit; // set inherit from config data.
this._bind = config.bind; // set the bind from the config data.
this._uid = config.uid; // set the uid options
this._events = config.events; // set the core system events
this._feature = config.feature; // set the feature from config data.
this._features = config.features; // set the features from config data.
this._zone = config.zone; // set the current zone from config data.
this._zones = config.zones; // set the zones from config data.
// load any custom zones from the agent file
if (this._agent.zones) {
for (let item in this._agent.zones) {
if (!this._zones[item]) this._zones[item] = this._agent.zones[item];
}
delete this._agent.zones;
}
this._action = config.action; // set the action from config data.
this._actions = config.actions; // set the actions from config data.
// load any custom actions from the agent file
if (this._agent.actions) {
for (let item in this._agent.actions) {
if (!this._actions[item]) this._actions[item] = this._agent.actions[item];
}
delete this._agent.actions;
}
this._state = config.state; // set the current state from config data.
this._states = config.states; // set the states from options
// load any custom actions from the agent file
if (this._agent.actions) {
for (let item in this._agent.actions) {
if (!this._actions[item]) this._actions[item] = this._agent.actions[item];
}
delete this._agent.actions;
}
this._context = config.context || false; // set the local context
this._messages = config.messages; // set the messages from config data.
// load any custom actions from the agent file
if (this._agent.messages) {
for (let item in this._agent.messages) {
if (!this._messages[item]) this._messages[item] = this._agent.messages[item];
}
delete this._agent.messages;
}
}
/**************
func: _assignBind
params: none
describe:
The assign bind function will bind the translate functions and parse functions
of the agent and bind their functionality to the state machine.
***************/
_assignBind() {
return new Promise((resolve, reject) => {
try {
this._bind.forEach(bind => { // loop over the bind items func, method, listener...
if (this[bind]) for (let x in this[bind]) { // if the root has a bind func, method, listener
if (typeof this[bind][x] === 'function') { // check to make sure object is a fucntion
this[bind][x] = this[bind][x].bind(this); // bind the item from the bind object
}
}
});
}
catch (e) {
return this.err(e, false, reject); // trigger the this.err for errors
}
finally {
return resolve(); // when the configuration is complete then return an empty resolve.
}
});
}
/**************
func: _assignListeners
params: none
describe:
Assign listeners will take the this.lisners objects and assign the appropriate
lisnter values for the event bus.
***************/
_assignListeners() {
return new Promise((resolve, reject) => {
try {
// set the default listeners for the states of the agent.
for (let state in this._states) {
if (typeof this[state] === 'function') {
this.events.on(`${this._agent.key}:${state}`, packet => {
return this[state](packet);
});
}
}
// set the assigned listeners for the agent.
for (let listener in this.listeners) { // loop over the liteners
this.events.on(listener, packet => { // set the event listener
return this.listeners[listener](packet); // return the listener function
})
}
}
catch (e) {
return this.err(e, false, reject); // pass errors to this.err
}
finally {
return resolve(); // resolve the function after everything is done.
}
});
}
// Some elements will inherit the data of the parent. this object will loop over
// any children data that theis deva has and assign the inherited information.
/**************
func: _assignInherit
params: none
describe:
The assign inherit will make sure the Devas in the current Deva have all the
inherited properties all setup to collaborate efficiently.
***************/
_assignInherit() {
return new Promise((resolve, reject) => {
try {
for (let d in this.devas) {
this._inherit.forEach(inherit => {
this.devas[d][inherit] = this[inherit];
});
}
return resolve();
}
catch (e) {
return this.err(e, false, reject);
}
});
}
// General handler for when a method is NOT found from a user command.
/**************
func: _methodNotFound
params:
- packet: The packet to relay when a method is not found.
describe:
The _methodNotFound function allows for additional security by firing
a specfici program functon every single time a interaction happens wehre a
method is not located. This assits in security and support by identifying
troubls or users who may be attemptng to explit features.
Then we talk a security event that watches all methods and return the packet.
This will return a not found text string preventing any furhter processing.
***************/
_methodNotFound(packet) {
if (!this._active) return this._messages.offline; // check the active status
const id = this.uid();
const agent = this.agent() || false;
const client = this.client() || false;
const {meta, params} = packet.q;
const text = `${this._messages.method_not_found} ${agent.key} ${meta.method}`
packet.a = {
id,
agent,
client,
text,
meta: {
key: agent.key,
method: meta.method,
},
created: Date.now(),
};
this.action('hash', `md5:${packet.a.id.uid}`);
packet.a.md5 = this.hash(packet.a, 'md5');
this.action('hash', `sha256:${packet.a.id.uid}`);
packet.a.sha256 = this.hash(packet.a, 'sha256');
this.action('hash', `sha512:${packet.a.id.uid}`);
packet.a.sha512 = this.hash(packet.a, 'sha512');
delete packet.md5;
delete packet.sha256;
delete packet.sha512;
packet.md5 = this.hash(packet, 'md5');
packet.sha256 = this.hash(packet, 'sha256');
packet.sha512 = this.hash(packet, 'sha512');
this.state('invalid', `${meta.method}:${packet.id.uid}`);
return packet;
}
_getFeature(key, value) {
if (!this._active) return this._messages.offline; // check the active status
this.zone(key);
this.feature(key); // set the security state
this.action(key);
this.state(key);
try {
const data = this.lib.copy(value);
this.state('return', key); // set the security state
return data; // return the security feature
} catch (e) {
this.state('catch', key);
return this.err(e);
}
}
/**************
func: Client
params: client - client provided data.
describe:
The Client feature sets up the client variables and removes any unnecessary
keys from the client object that are used in other features.
usage:
this.Client = {data}
***************/
Client(client, resolve, reject) {
this.feature('client', `client:${client.id}`);
this.zone('client', `client:${client.id}`);
this.action('client', `client:${client.id}`);
// setup any custom methods for the features
this.state('set', `client:feature:methods:${client.id}`);
try {
for (const x in client.features) {
const methods = client.features[x].methods || false;
if (methods) for (const y in methods) {
const isFunc = typeof methods[y] === 'function';
if (isFunc) {
this.methods[y] = methods[y].bind(this);
}
}
}
const _client = this.lib.copy(client); // copy the client parameter
this.state('data', `client:${client.id}`);
this._client = _client; // set local _client to this scope
this.action('return', `client:${client.id}`);
return resolve();
} catch (e) {
this.action('investigate', `client:${client.id}`);
return this.err(e, false, reject);
}
}
/**************
func: Feature
params: client: false
describe:
The Security feature sets the correct variables and necessary rules for the
client presented data.
***************/
Feature(feature, resolve, reject) {
const _id = this.uid();
this.feature(feature, _id.uid);
this.zone(feature, _id.uid);
const _cl = this.client(); // set local copy of client data
try {
if (!_cl.features[feature]) return resolve(); // if no security feature goto Support
else {
this.action(feature, _id.uid); // set action to feature
const _fe = `_${feature}`;
const {id, profile, features} = _cl; // make a copy the clinet data.
const data = features[feature]; // make a copy the clinet data.
this.state(feature, _id.uid);
this[_fe] = { // set this feature with data
id: _id, // uid of the feature
client_id: id, // client id for reference
client_name: profile.name, // client name for personalization
concerns: data.concerns, // any concerns for client
global: data.global, // the global policies for client
personal: data.devas[this._agent.key], // Client personal features and rules.
created: Date.now(),
};
delete this._client.features[feature]; // make a copy the clinet data.
this.state('resolve', `${feature}:${_id.uid}`);
return resolve(feature); // resolve when done
}
} catch (e) {
this.state('catch', `${feature}:${_id.uid}`);
return this.err(e, feature, reject); // run error handling if an error is caught
}
}
/**************
func: Indra
params: resolve, reject
describe:
The Indra feature sets the correct variables and necessary rules for the
client presented data.
***************/
Indra(resolve, reject) {
return this.Feature('indra', resolve, reject);
}
/**************
func: Veda
params: resolve, reject
describe:
The Veda feature sets the correct variables and necessary rules for the
client presented data.
***************/
Veda(resolve, reject) {
return this.Feature('veda', resolve, reject);
}
/**************
func: License
params: resolve, reject
describe:
The License feature sets the correct variables and necessary rules for the
client presented data.
***************/
License(resolve, reject) {
return this.Feature('license', resolve, reject);
}
/**************
func: Data
params: resolve, reject
describe:
The Data feature sets the correct variables and necessary rules for the
client presented data.
***************/
Data(resolve, reject) {
return this.Feature('data', resolve, reject);
}
/**************
func: Error
params: resolve, reject
describe:
The Error feature sets the correct variables and necessary rules for the
client presented data.
***************/
Error(resolve, reject) {
return this.Feature('error', resolve, reject);
}
/**************
func: Log
params: resolve, reject
describe:
The Log feature sets the correct variables and necessary rules for the
client presented data.
***************/
Log(resolve, reject) {
return this.Feature('log', resolve, reject);
}
/**************
func: Report
params: resolve, reject
describe:
The Report feature sets the correct variables and necessary rules for the
client presented data.
***************/
Report(resolve, reject) {
return this.Feature('report', resolve, reject);
}
/**************
func: Vector
params: resolve, reject
describe:
The Vector feature sets the correct variables and necessary rules for the
client presented data.
***************/
Vector(resolve, reject) {
return this.Feature('vector', resolve, reject);
}
/**************
func: King
params: resolve, reject
describe:
The King feature sets the correct variables and necessary rules for the
client presented data.
***************/
King(resolve, reject) {
return this.Feature('king', resolve, reject);
}
/**************
func: Owner
params: resolve, reject
describe:
The Owner feature sets the correct variables and necessary rules for the
client presented data.
***************/
Owner(resolve, reject) {
return this.Feature('owner', resolve, reject);
}
/**************
func: Treasury
params: resolve, reject
describe:
The Treasury feature sets the correct variables and necessary rules for the
client presented data.
***************/
Treasury(resolve, reject) {
return this.Feature('treasury', resolve, reject);
}
/**************
func: Security
params: resolve, reject
describe:
The Security feature sets the correct variables and necessary rules for the
client presented data.
***************/
Security(resolve, reject) {
return this.Feature('security', resolve, reject);
}
/**************
func: Guard
params: resolve, reject
describe:
The Guard feature sets the correct variables and necessary rules for the
client presented data.
***************/
Guard(resolve, reject) {
return this.Feature('guard', resolve, reject);
}
/**************
func: Defense
params: resolve, reject
describe:
The Defense feature sets the correct variables and necessary rules for the
client presented data.
***************/
Defense(resolve, reject) {
return this.Feature('defense', resolve, reject);
}
/**************
func: Wall
params: resolve, reject
describe:
The Defense feature sets the correct variables and necessary rules for the
client presented data.
***************/
Wall(resolve, reject) {
return this.Feature('wall', resolve, reject);
}
/**************
func: Shield
params: resolve, reject
describe:
The Shield feature sets the correct variables and necessary rules for the
client presented data.
***************/
Shield(resolve, reject) {
return this.Feature('shield', resolve, reject);
}
/**************
func: Proxy
params: resolve, reject
describe:
The Defense feature sets the correct variables and necessary rules for the
client presented data.
***************/
Proxy(resolve, reject) {
return this.Feature('proxy', resolve, reject);
}
/**************
func: Legal
params: resolve, reject
describe:
The Legal feature sets the correct variables and necessary rules for the
client presented data.
***************/
Legal(resolve, reject) {
return this.Feature('legal', resolve, reject);
}
/**************
func: Justice
params: resolve, reject
describe:
The Justice feature sets the correct variables and necessary rules for the
client presented data.
***************/
Justice(resolve, reject) {
return this.Feature('justice', resolve, reject);
}
/**************
func: Authority
params: resolve, reject
describe:
The Authority feature sets the correct variables and necessary rules for the
client presented data.
***************/
Authority(resolve, reject) {
return this.Feature('authority', resolve, reject);
}
/**************
func: Support
params: resolve, reject
describe:
The Support feature sets the correct variables and necessary rules for the
client presented data.
***************/
Support(resolve, reject) {
return this.Feature('support', resolve, reject);
}
/**************
func: Services
params: resolve, reject
describe:
The Services feature sets the correct variables and necessary rules for the
client presented data.
***************/
Services(resolve, reject) {
return this.Feature('services', resolve, reject);
}
/**************
func: Systems
params: client: false
describe:
The Systems feature sets the correct variables and necessary rules for the
client presented data.
***************/
Systems(resolve, reject) {
return this.Feature('systems', resolve, reject);
}
/**************
func: Networks
params: resolve, reject
describe:
The Networks feature sets the correct variables and necessary rules for the
client presented data.
***************/
Networks(resolve, reject) {
return this.Feature('networks', resolve, reject);
}
/**************
func: Done
params: none
describe: The end of the workflow Client Feature Workflow
***************/
Done(resolve, reject) {
try {
delete this._client.features; // delete the features key when done.
this.state('Done', 'Done'); // set the done state.
return resolve(this._client); // resolve an empty pr
} catch (e) {
this.state('catch', 'Done');
return this.err(e, false, reject);
}
}
/**************
func: talk
params:
- evt: The event the Deva is speaking to listen back for on a once event.
- resource: The payload resource to send with the talk event.
describe:
The talk event allows agents to broadcast events that other Deva can listen
to and make a response. talk events can be then returned with a talk even id
to create seamless collaboration between Devas.
***************/
talk(evt, packet=false) {
return this.events.emit(evt, packet);
}
/**************
func: listen
params:
- evt: The vent label to listen for
- callback: The callback function to run when the event fires.
describe: setup a new event listener in the system.
***************/
listen(evt, callback) {
this.action('listen', evt);
this.listeners[evt] = callback;
return this.events.on(evt, packet => {
return this.listeners[evt](packet);
});
}
/**************
func: once
params:
- evt: The event to listen to for a once call.
- callback: The callback functoin to run when the event fires.
describe:
***************/
once(evt, callback) {
this.action('once', evt)
return this.events.once(evt, callback);
}
/**************
func: ignore
params:
- evt: The event you'd like to ignore.
- callback: a callback function to execute after removing the event from listerns.
describe: The ignore function allow the removal of events in the listener group.
***************/
ignore(evt, callback) {
this.action('ignore', evt);
return this.events.removeListener(evt, callback);
}
/**************
func: question
example: this.question('#*agent.key *method* *text*')
example: this.question('#*agent.key* *method* *properties*', {*data*})
params:
= TEXT: The text string is the question to process in the current state.
- DATA: The data is a data array or object that also can be passed to the question.
describe:
***************/
question(TEXT=false, DATA=false) {
const id = this.uid(); // generate a unique id for transport.
// check the active status
if (!this._active) return Promise.resolve(this._messages.offline);
this.zone('question', id.uid);
this.action('question', id.uid);
const t_split = TEXT.split(' '); // split the text on spaces to get words.
const data = DATA; // set the DATA to data
// check to see if the string is an #ask string to talk to the other Deva.
const isAsk = t_split[0].startsWith(this.askChr);
// check to see if the string is a command string to run a local method.
const isCmd = t_split[0].startsWith(this.cmdChr);
// Format the packet for return on the request.
const packet = { // create the base q/a packet
id, // set the id into packet
q: false, // create empty q object in packet
a: false, // create empty a object in packet
created: Date.now(), // timestamp the packet
};
let text = TEXT, // let TEXT is text for a manipulation variable
params = false, // params as false to build params string
method = 'question', // set the default method to question
key = this.agent().key; // set a temporary key from the agent key.
return new Promise((resolve, reject) => {
// resolve with the no text message if the client says nothing.
if (!TEXT) return resolve(this._messages.notext, resolve);
this.state('try', `question:${id.uid}`);
try { // try to answer the question
if (isAsk) { // determine if hte question isAsk
// if:isAsk split the agent key and remove first command character
key = t_split[0].substring(1);
//if:isAsk use text split index 1 as the parameter block
params = t_split[1] ? t_split[1].split(':') : false;
method = params[0]; // the method to check is then params index 0
text = t_split.slice(2).join(' ').trim(); // rejoin the text with space
this.state('ask', `${key}:${method}:${id.uid}`);
}
else if (isCmd) { // determine if the question is a command
//if:isCmd use text split index 1 as the parameter block
params = t_split[0] ? t_split[0].split(':') : false;
method = t_split[0].split(':')[0].substring(1); // if:isCmd use the 0 index as the command
text = t_split.slice(1).join(' ').trim(); // if:isCmd rejoin the string on the space after removing first index
this.state('cmd', `${method}:${id.uid}`); // set the state to cmd.
}
this.state('set', `question:${method}:${id.uid}`)
packet.q = { // build packet.q container
id: this.uid(), // set the transport id for the question.
agent: this.agent(), // set the agent
client: this.client(), // set the client
meta: { // build the meta container
key, // set the key variable
method, // set method to track function use
params, // set any params that are associated
},
text, // set the text for the packet.
data, // set the data object
created: Date.now(), // timestamp the question
}
// hash the question
packet.q.md5 = this.hash(packet.q, 'md5');
packet.q.sha256 = this.hash(packet.q, 'sha256');
packet.q.sha512 = this.hash(packet.q, 'sha512');
this.talk(this._events.question, this.lib.copy(packet)); // global question event make sure to copy data.
if (isAsk) { // isAsk check if the question isAsk and talk
// if: isAsk wait for the once event which is key'd to the packet ID for specified responses
this.talk(`${key}:ask`, packet);
this.once(`${key}:ask:${packet.id.uid}`, answer => {
this.talk(this._events.ask, this.lib.copy(answer));
this.state('return', `${key}:ask:${packet.id.uid}`);
return this.finish(answer, resolve); // if:isAsk resolve the answer from the call
});
}
else { // else: answer the question locally
this.state('answer', `${method}:${id.uid}`); //set the answer state to the method
return this.answer(packet, resolve, reject);
}
}
catch(e) {
this.state('catch', `${id.uid}`);
return this.err(e); // if a overall error happens this witll call this.err
}
});
}
/**************
func: answer
params:
- packet
- resolve
- reject
describe:
The answer function is called from the question function to return an answer
from the agent from the pre-determined method.
***************/
answer(packet, resolve, reject) {
const id = this.uid();
if (!this._active) return Promise.resolve(this._messages.offline);
this.zone('answer', id.uid); // set zone to answer
const agent = this.agent();
const client = this.client();
// check if method exists and is of type function
const {method,params} = packet.q.meta;
this.action('answer', `${method}:${id.uid}`);
this.state('try', `answer:${method}:${id.uid}`);
try {
const isMethod = this.methods[method] && typeof this.methods[method] == 'function';
if (!isMethod) return resolve(this._methodNotFound(packet)); // resolve method not found if check if check fails
this.action('method', `answer:${method}:${id.uid}`);
this.methods[method](packet).then(result => {
// check the result for the text, html, and data object. // this is for when answers are returned from nested Devas.
const text = typeof result === 'object' ? result.text : result;
const html = typeof result === 'object' ? result.html : result;
// if the data passed is NOT an object it will FALSE
const data = typeof result === 'object' ? result.data : false;
this.state('set', `answer:${method}:packet_answer:${id.uid}`);
const packet_answer = { // setup the packet.a container
id,
agent, // set the agent who answered the question
client, // set the client asking the question
meta: { // setup the answer meta container
key: agent.key, // set the agent key inot the meta
method, // set the method into the meta
params, // set the params into the meta
},
text, // set answer text
html, // set the answer html
data, // set the answer data
created: Date.now(), // set the created date for the answer
};
// create a hash for the answer and insert into answer meta.
packet_answer.md5 = this.hash(packet_answer, 'md5');
packet_answer.sha256 = this.hash(packet_answer, 'sha256');
packet_answer.sha512 = this.hash(packet_answer, 'sha512');
packet.a = packet_answer; // set the packet.a to the packet_answer
this.talk(this._events.answer, this.lib.copy(packet)); // global talk event
this.state('return', `answer:${method}:${id.uid}`); // set the state resolve answer
return this.finish(packet, resolve); // resolve the packet to the caller.
}).catch(err => { // catch any errors in the method
this.state('catch', `answer:${method}:${id.uid}`); // set the state reject answer
return this.err(err, packet, reject); // return this.err with err, packet, reject
});
} catch (e) {
this.state('catch', `answer:${method}:${id.uid}`);
return this.err(e, packet, reject);
}
}
/**************
func: ask
params: packet
describe:
The ask function gives each agent the ability to ask question to other agents
in the system. When a question is asked the Agent with the question if it
detect an ask event it will trigger. Then if an Agent with the matching ask
event is listening they will respond. The question function uses this to
create integrated communication between itself and other Deva in it's library.
It can also be used in a custom manner to broadcast ask events inside other coe aswell.
When the talk has an answer it will respond with a talk event that has the packet id
so the event is specific to the talk.
***************/
ask(packet) {
if (!this._active) return Promise.resolve(this._messages.offline);
const agent = this.agent();
const client = this.client();
const {method, params} = packet.q.meta;
this.zone('ask', `${method}:${packet.id.uid}`);
this.action('ask', `${method}:${packet.id.uid}`);
// build the answer packet from this model
this.state('try', `ask:${method}:${packet.id.uid}`);
try {
if (typeof this.methods[method] !== 'function') {
return setImmediate(() => {
this.talk(`${this._agent.key}:ask:${packet.id.uid}`, this._methodNotFound(packet));
});
}
this.state('set', `ask:${method}:packet_answer:${packet.id.uid}`);
const packet_answer = {
id: this.uid(),
agent,
client,
meta: {
key: agent.key,
method,
params,
},
text: false,
html: false,
data: false,
created: Date.now(),
};
// The method is parsed and depending on what method is asked for it returns
// the response based on the passed through packet.
this.methods[method](packet).then(result => {
if (typeof result === 'object') {
packet_answer.text = result.text || false;
packet_answer.html = result.html || false;
packet_answer.data = result.data || false;
}
else {
packet_answer.text = result;
}
packet_answer.md5 = this.hash(packet_answer, 'md5'); // md5 the answer.
packet_answer.sha256 = this.hash(packet_answer, 'sha256'); // sha256 the answer.
packet_answer.sha512 = this.hash(packet_answer, 'sha512'); // sha512 the answer
packet.q.agent = agent; // set the question agent as the ask agent.
packet.a = packet_answer; // set the packet answer.
// delete previous hashes before creating new ones.
delete packet.md5;
delete packet.sha256;
delete packet.sha512;
// create new hashes for the packet before return.
packet.md5 = this.hash(packet, 'md5');
packet.sha256 = this.hash(packet, 'sha256');
packet.sha512 = this.hash(packet, 'sha512');
this.talk(this._events.answer, this.lib.copy(packet)); // global talk event
this.talk(`${agent.key}:ask:${packet.id.uid}`, packet);
}).catch(err => {
this.talk(`${agent.key}:ask:${packet.id.uid}`, {error:err});
this.state('catch', `ask:${method}:${packet.id.uid}`);
return this.err(err, packet);
})
}
catch (e) {
this.state('catch', `ask:${method}:${packet.id.uid}`);
this.talk(`${agent.key}:ask:${packet.id.uid}`, {error:e});
return this.err(e, packet)
}
// now when we ask the meta params[0] should be the method
}
/**************
func: init
params: client - the client data to use that is provided by the clients.
describe:
The main init interface where the chain begins. Where the states fire for
each process of setting:
1. Set the Max listeners to control event memory buffer.
2. Assign the Inherited Properties
3. Assign binding functions and methods to 'this' scope.
4. Assign any listeners for additional functionality.
5. run the onInit custom function if preset or the start function.
6. The start function will create a chain reaction of states that load.
7. If there is an error the init function rejects the call.
usage: this.init(client_object)
***************/
init(client) {
// set client
this._active = Date.now();
const agent = this.agent();
const data = {
id: this.uid(),
key: 'init',
value: agent.key,
agent,
client,
text: this._messages.init,
created: Date.now(),
}
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
return new Promise((resolve, reject) => {
const license_check = this.license_check(client.VLA, this._core.VLA);
if (!license_check) {
this.prompt(this._messages.client_license_invalid);
return resolve(this._messages.client_license_invalid); // return if} license check fails
}
this.events.setMaxListeners(this.maxListeners);
this._assignInherit().then(() => {
return this._assignBind();
}).then(() => {
return this._assignListeners();
}).then(() => {
this.feature('init');
this.zone('init');
this.action('init');
this.state('init');
}).then(() => {
return this.Client(client, resolve, reject);
}).then(() => {
return this.Indra(resolve, reject);
}).then(() => {
return this.Veda(resolve, reject);
}).then(() => {
return this.License(resolve, reject);
}).then(() => {
return this.Data(resolve, reject);
}).then(() => {
return this.Error(resolve, reject);
}).then(() => {
return this.Log(resolve, reject);
}).then(() => {
return this.Report(resolve, reject);
}).then(() => {
return this.Vector(resolve, reject);
}).then(() => {
return this.King(resolve, reject);
}).then(() => {
return this.Owner(resolve, reject);
}).then(() => {
return this.Treasury(resolve, reject);
}).then(() => {
return this.Security(resolve, reject);
}).then(() => {
return this.Guard(resolve, reject);
}).then(() => {
return this.Defense(resolve, reject);
}).then(() => {
return this.Wall(resolve, reject);
}).then(() => {
return this.Shield(resolve, reject);
}).then(() => {
return this.Proxy(resolve, reject);
}).then(() => {
return this.Legal(resolve, reject);
}).then(() => {
return this.Authority(resolve, reject);
}).then(() => {
return this.Justice(resolve, reject);
}).then(() => {
return this.Support(resolve, reject);
}).then(() => {
return this.Services(resolve, reject);
}).then(() => {
return this.Systems(resolve, reject);
}).then(() => {
return this.Networks(resolve, reject);
}).then(() => {
return this.Done(resolve, reject);
}).then(() => {
const hasOnInit = this.onInit && typeof this.onInit === 'function';
this.state('return', `init:${data.id.uid}`);
return hasOnInit ? this.onInit(data, resolve) : this.start(data, resolve);
}).catch(err => {
this.state('catch', `init:${data.id.uid}`);
return this.err(err, client, reject);
});
});
}
/**************
func: start
params:
- msg: the message for use when using custome flow logic to pass to onEnter
describe:
The start function begins the process by setting the state to start setting
the active to the current datetime and then checking for a custom onStart
function or running the enter function.
usage: this.start('msg')
***************/
start(data, resolve) {
this.context('start', data.id.uid);
this.zone('start', data.id.uid);
if (!this._active) return resolve(this._messages.offline);
this.action('start', data.id.uid);
const id = this.uid();
delete data.md5;
delete data.sha256;
delete data.sha512;
data.value = 'start';
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
const hasOnStart = this.onStart && typeof this.onStart === 'function' ? true : false;
this.state('start', data.id.uid);
this.talk(this._events.start, data);
return hasOnStart ? this.onStart(data, resolve) : this.enter(data, resolve)
}
/**************
func: enter
params:
- msg: the message from the caller incase need to use in calls
describe:
The enter function will check the active status of the Deva and set it to
offline or enter.
If the Deva is offline it will return the offline message.
usage: this.enter('msg')
***************/
enter(data, resolve) {
this.context('enter', data.id.uid);
this.zone('enter', data.id.uid);
if (!this._active) return resolve(this._messages.offline);
this.action('enter', data.id.uid);
const hasOnEnter = this.onEnter && typeof this.onEnter === 'function' ? true : false;
delete data.md5;
delete data.sha256;
delete data.sha512;
data.value = 'enter';
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('enter', data.id.uid);
this.talk(this._events.enter, data);
return hasOnEnter ? this.onEnter(data, resolve) : this.done(data, resolve)
}
/**************
func: done
params:
- data: hte message from the caller incase need to use in calls
describe:
When the done function is triggered the system will also set the state
of hte Deva to done.
If the deva is offline it will return the offline message.
usage: this.done('msg')
***************/
done(data, resolve) {
this.context('done', data.id.uid);
this.zone('done', data.id.uid);
if (!this._active) return resolve(this._messages.offline);
this.action('done', data.id.uid);
const hasOnDone = this.onDone && typeof this.onDone === 'function' ? true : false;
delete data.md5;
delete data.sha256;
delete data.sha512;
data.value = 'done';
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('done', data.id.uid);
this.talk(this._events.done, data);
return hasOnDone ? this.onDone(data, resolve) : this.ready(data, resolve);
}
/**************
func: ready
params:
- data: the data to pass to the resolve
- resolve: the complete resolve to pass back
describe: This function is use to relay the to the ready state.
usage: this.ready(data, resolve)
***************/
ready(data, resolve) {
this.context('ready', data.id.uid);
this.zone('ready', data.id.uid);
if (!this._active) return resolve(this._messages.offline);
this.action('ready', data.id.uid);
const hasOnReady = this.onReady && typeof this.onReady === 'function';
// Delete previous data hashes
delete data.md5;
delete data.sha256;
delete data.sha512;
data.value = 'ready';
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('ready', data.id.uid);
this.talk(this._events.ready, data);
this.zone('home', `client:home:${data.id.uid}`);
return hasOnReady ? this.onReady(data, resolve) : resolve(data);
}
/**************
func: finish
params:
- data: the data to pass to the resolve
- resolve: the finish resolve to pass back
describe: This function is used to relay into the finish state when resolving a question or data.
usage: this.finish(data, resolve)
***************/
finish(data, resolve) {
if (!this._active) return resolve(this._messages.offline); //
this.context('finish', data.id.uid);
this.zone('finish', data.id.uid); // enter finish zone
this.action('finish', data.id.uid); // start finish action
const hasOnFinish = this.onFinish && typeof this.onFinish === 'function';
delete data.md5;
delete data.sha256;
delete data.sha512;
data.finish = Date.now(); // set the finish timestamp
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('finish', data.id.uid); // set finish state
this.talk(this._events.finish, data);
return hasOnFinish ? this.onFinish(data, resolve) : this.complete(data, resolve);
}
/**************
func: complete
params:
- data: the data to pass to the resolve
- resolve: the complete resolve to pass back
describe: This function is use to relay into a complete state when
resolving a question or data.
usage: this.complete(data, resolve)
***************/
complete(data, resolve) {
if (!this._active) return Promise.resolve(this._messages.offline);
this.context('complete', data.id.uid);
this.zone('complete', data.id.uid);
this.action('complete', data.id.uid);
const hasOnComplete = this.onComplete && typeof this.onComplete === 'function';
delete data.md5;
delete data.sha256;
delete data.sha512;
data.complete = Date.now();// set the complete date on the whole data.
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('complete', data.id.uid);
this.talk(this._events.complete, data);
return hasOnComplete ? this.onComplete(data, resolve) : resolve(data);
}
/**************
func: stop
params:
- msg: hte message from the caller incase need to use in calls
describe:
The stop function will stop the Deva by setting the active status to false,
and the state to stop. From here it will check for a custom onStop function
for anything to run, or run the exit function.
If the deva is offline it will return the offline message.
usage:
this.stop()
***************/
stop() {
if (!this._active) return Promise.resolve(this._messages.offline);
const id = this.uid();
this.context('stop', id);
this.zone('stop', id);
this.action('stop', id);
const hasOnStop = this.onStop && typeof this.onStop === 'function';
const data = { // build the stop data
id, // set the id
key: 'stop', // set the key
value: this._messages.stop, // set the value
agent: this.agent(), // set the agent
client: this.client(), // set the client
created: Date.now(), // set the created date
}
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
// has stop function then set hasOnStop variable
// if: has on stop then run on stop function or return exit function.
this.state('stop', id); // set the state to stop
this.talk(this._events.stop, data);
return hasOnStop ? this.onStop(data) : this.exit()
}
/**************
func: exit
params:
- msg: hte message from the caller incase need to use in calls
describe:
The exit state function is triggered when the Deva is exiting.
The return will check for a custom onExit function or run the done
function.
***************/
exit() {
if (!this._active) return Promise.resolve(this._messages.offline);
const id = this.uid();
this.context('exit', id);
this.zone('exit', id);
this.action('exit', id);
const hasOnExit = this.onExit && typeof this.onExit === 'function';
const data = {
id,
key: 'exit',
value: this._messages.exit,
agent: this.agent(),
client: this.client(),
created: Date.now(),
}
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('exit', id); // set the state to stop
this.talk(this._events.exit, data);
// clear memory
this._active = false;
this._client = false;
this._vector = false;
this._data = false;
this._treasury = false;
this._security = false;
this._guard = false;
this._defense = false;
this._wall = false;
this._shield = false;
this._proxy = false;
this._legal = false;
this._authority = false;
this._justice = false;
this._support = false;
this._services = false;
this._systems = false;
this._networks = false;
return hasOnExit ? this.onExit(data) : Promise.resolve(data)
}
////////////////////////////
/**************
func: state
params:
- value: The state value to set for the Deva that matches to this._states
- extra: any extra text to add ot the state change.
***************/
state(value=false, extra=false) {
try {
if (!value || !this._states[value]) return; // return if no matching value
this._state = value; // set the local state variable.
const lookup = this._states[value]; // set the local states lookup
const text = extra ? `${lookup} ${extra}` : lookup; // set text from lookup with extra
const data = { // build the data object
id: this.uid(), // set the data id
agent: this.agent(), // set the agent
client: this.client(), // set the client
key: 'state', // set the key to state
value, // set the value to the passed in value
text, // set the text value of the data
created: Date.now(), // set the data created date.
};
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.talk(this._events.state, data); // broadcasat the state event
return data;
} catch (e) { // catch any errors
return this.err(e); // return if an error happens
}
}
/**************
func: states
params: none
describe: returns the avaiable staets values.
***************/
states() {
const id = this.uid();
this.action('states', id);
const data = {
id,
key: 'states',
value: this._states,
created: Date.now(),
}
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.state('return', `states:${id.uid}`);
return data;
}
/**************
func: zone
params:
- st: The zone flag to set for the Deva that matches to this._zones
describe
***************/
zone(value=false, extra=false) {
const id = this.uid();
if (!value || !this._zones[value]) return;
try {
this._zone = value;
const lookup = this._zones[value]; // set the lookup value
const text = extra ? `${lookup} ${extra}` : lookup; // set the text value
const data = { // build the zone data
id, // set the packetid
agent: this.agent(),
client: this.client(),
key: 'zone',
value,
text,
created: Date.now(),
};
data.md5 = this.hash(data);
data.sha256 = this.hash(data, 'sha256');
data.sha512 = this.hash(data, 'sha512');
this.talk(this._events.zone, data);
return data;
} catch (e) {
this.state('catch', `zone:${value}:${id.uid}`);
return this.err(e, value);
}
}
/**************
func: zones
params: none
describe: returns a listing of zones currently in the system.
***************/
zones() {
const id = this.uid();
this.action('zones', id.uid);
this.state('return', `zones:${id.uid}`);
const data = {
id, // set the uuid of the data
agent: this.agent(), // set the agent value
cleint: this.client(), // set the client value
key: 'zones', // set the key return value
value: this._zones, // set the list of zones
created: Date.now(), // set the created date of the object.
}
data.md5 = this.hash(data);