UNPKG

6.12 kBJavaScriptView Raw
1/**
2 * @module actors management
3 */
4
5var EventEmitter = require('events').EventEmitter;
6
7var properties = require('./properties');
8var logger = require('./logger')('hubiquitus:core:actors');
9var utils = {
10 aid: require('./utils/aid'),
11 uuid: require('./utils/uuid'),
12 misc: require('./utils/misc')
13};
14var _ = require('lodash');
15
16exports.__proto__ = new EventEmitter();
17exports.setMaxListeners(0);
18
19/**
20 * @type {object}
21 */
22var actors = {};
23
24/**
25 * @type {object}
26 */
27var bareActors = {};
28
29/**
30 * @enum {string}
31 */
32exports.scope = {
33 PROCESS: 'process',
34 LOCAL: 'local',
35 REMOTE: 'remote',
36 ALL: 'all'
37};
38
39/**
40 * Adds actor in cache
41 * @param actor {object} actor to add
42 * @param [scope] {string} requested actor scope (forced if provided)
43 */
44exports.add = function (actor, scope) {
45 if (utils.aid.isBare(actor.id)) actor.id += '/' + utils.uuid();
46
47 if (exports.exists(actor)) return;
48
49 actor.scope = scope || computeScope(actor);
50 actors[actor.id] = actor;
51
52 var bare = utils.aid.bare(actor.id);
53 if (!bareActors[bare]) bareActors[bare] = [];
54 bareActors[bare].push(actor.id);
55
56 logger.makeLog('trace', 'hub-32', 'actor ' + actor.id + ' added !', {actor: actor});
57 exports.emit('actor added', actor.id, actor.scope);
58};
59
60/**
61 * Enhance actor with its scope if not already computed
62 * @param {object} actor
63 * @return {string} scope
64 */
65function computeScope(actor) {
66 var scope = exports.scope.REMOTE;
67 if (actor.container.netInfo.pid === properties.netInfo.pid && actor.container.netInfo.ip === properties.netInfo.ip) {
68 scope = exports.scope.PROCESS;
69 } else if (actor.container.netInfo.ip === properties.netInfo.ip) {
70 scope = exports.scope.LOCAL;
71 }
72 return scope;
73}
74
75/**
76 * Removes actor from cache
77 * @param aid {string} actor to remove
78 * @param [scope] {string} requested actor scope
79 */
80exports.remove = function (aid, scope) {
81 scope = scope || exports.scope.ALL;
82
83 var toRemove = [];
84 var bares = null;
85 if (utils.aid.isBare(aid)) {
86 bares = bareActors[aid];
87 if (bares) {
88 var aids = _.filter(bares, function (item) {
89 return exports.inScope(item, scope);
90 });
91 _.forEach(aids, function (item) {
92 _.remove(bares, item);
93 var actor = actors[item];
94 actor && toRemove.push({id: actor.id, scope: actor.scope});
95 });
96 } else {
97 logger.makeLog('trace', 'hub-44', 'cant remove bare actor ' + aid + ': no matching full aid');
98 }
99 } else {
100 var actor = actors[aid];
101 if (actor) {
102 var bare = utils.aid.bare(aid);
103 bares = bareActors[bare];
104 _.remove(bares, function (item) {
105 return item === aid && exports.inScope(item, scope);
106 });
107 toRemove.push({id: actor.id, scope: actor.scope});
108 } else {
109 logger.makeLog('trace', 'hub-34', 'cant remove non existing actor ' + aid);
110 }
111 }
112 _.forEach(toRemove, function (item) {
113 logger.makeLog('trace', 'hub-33', 'actor ' + item.id + ' removed !', {actor: actor});
114 delete actors[item.id];
115 exports.emit('actor removed', item.id, item.scope);
116 });
117};
118
119/**
120 * Removes all actor related to given container
121 * @param cid {string} container aid
122 */
123exports.removeByContainer = function (cid) {
124 var aids = _.filter(_.keys(actors), function (currentAid) {
125 return actors[currentAid].container.id === cid;
126 });
127 _.forEach(aids, function (aid) {
128 exports.remove(aid);
129 });
130 logger.makeLog('trace', 'hub-35', 'actors owned by container ' + cid + ' removed !');
131};
132
133/**
134 * Returns actors in the given scope
135 * @param {string} scope
136 * @returns {Array} actors
137 */
138exports.all = function (scope) {
139 scope = scope || exports.scope.ALL;
140 return _.filter(_.keys(actors), function (aid) {
141 return exports.inScope(aid, scope);
142 });
143};
144
145/**
146 * Returns actor in cache
147 * @param aid {string} requested aid
148 * @param [scope] {string} requested actor scope
149 * @returns {object} actor
150 */
151exports.get = function (aid, scope) {
152 scope = scope || exports.scope.ALL;
153 var actor = actors[aid];
154 if (!actor || !exports.inScope(actor, scope)) {
155 actor = null;
156 }
157 return actor;
158};
159
160/**
161 * Get all actors in cache matching with given aid (all full aid matching given aid if bare)
162 * @param reqAid {string} requested aid
163 * @param [scope] {string} requested scope
164 * @returns {Array} matching aid collection
165 */
166exports.getAll = function (reqAid, scope) {
167 scope = scope || exports.scope.ALL;
168 var aids = [];
169 if (utils.aid.isFull(reqAid) && exports.inScope(reqAid, scope)) {
170 aids.push(reqAid);
171 } else {
172 aids = _.filter(_.keys(actors), function (currentAid) {
173 return utils.aid.bare(currentAid) === reqAid && exports.inScope(currentAid, scope);
174 });
175 }
176 return aids;
177};
178
179/**
180 * Checks that the actor exists
181 * @param reqActor {object|string} requested actor or aid
182 * @param [scope] {string} requested actor scope
183 * @returns {boolean} true if actor exists
184 */
185exports.exists = function (reqActor, scope) {
186 if (!_.isString(reqActor) && !_.isObject(reqActor)) return false;
187 var aid = _.isString(reqActor) ? reqActor : reqActor.id;
188 return exports.get(aid, scope) !== null;
189};
190
191/**
192 * Checks if an actor is in given scope
193 * @param reqActor {object|string} requested actor or aid
194 * @param scope {string} requested actor scope
195 * @returns {boolean} true if actor in scope
196 */
197exports.inScope = function (reqActor, scope) {
198 var inScope = false;
199 var actor = _.isString(reqActor) ? actors[reqActor] : actors[reqActor.id];
200 if (actor) {
201 inScope = (scope === exports.scope.ALL) ? true : (actor.scope === scope);
202 }
203 return inScope;
204};
205
206/**
207 * Pick an actor in cache
208 * Returns aid if existing in cache
209 * If requested aid is bare, returns a full aid picked randomly from the list of bare-matching aid in cache
210 * @param reqAid {string} requested aid
211 * @returns {string} aid or undefined
212 */
213exports.pick = function (reqAid) {
214 var aid = null;
215 if (utils.aid.isFull(reqAid)) {
216 if (actors[reqAid]) aid = reqAid;
217 } else {
218 var bareAids = bareActors[reqAid];
219 if (bareAids) {
220 aid = utils.misc.roundRobin('actors.pick|' + reqAid, bareAids);
221 }
222 }
223 return aid;
224};