Skip to content

Commit 0a5f881

Browse files
author
Vivek Kumar
committed
AppManager with priority in AppListener
1 parent c2f907f commit 0a5f881

9 files changed

Lines changed: 551 additions & 0 deletions

File tree

lib/AppListener.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2018 Vivek Kumar
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
var debug = require('debug')('appmanager:app-listener');
26+
27+
module.exports = AppListener;
28+
29+
function AppListener() {
30+
this.priority = 0;
31+
}
32+
33+
//default skeltion for preStart
34+
AppListener.prototype.preStart = function (next) {
35+
debug("default preStart called for class : %s", this.constructor.name);
36+
next();
37+
};
38+
39+
//default skeltion for onStart
40+
AppListener.prototype.onStart = function (next) {
41+
debug("default onStart called for class : %s", this.constructor.name);
42+
next();
43+
};
44+
45+
//default skeltion for postStart
46+
AppListener.prototype.postStart = function (next) {
47+
debug("default postStart called for class : %s", this.constructor.name);
48+
next();
49+
};
50+
51+
//default skeltion for onClose
52+
AppListener.prototype.onClose = function (type, exitCode) {
53+
debug("default onClose called for class : %s", this.constructor.name);
54+
};
55+
56+
//default skeltion for onError
57+
AppListener.prototype.onError = function (err) {
58+
debug("default onError called for class : %s", this.constructor.name);
59+
};
60+
61+

lib/AppManager.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2018 Vivek Kumar
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
var debug = require('debug')('appmanager:state');
26+
27+
var Filters = require('./Filters');
28+
var Scanner = require('./Scanner');
29+
var AppListener = require('./AppListener');
30+
31+
//just for internal use
32+
var ChainHandler = require('./ChainHandler');
33+
34+
35+
module.exports = AppManager;
36+
37+
module.exports.AppListener = AppListener;
38+
module.exports.Scanner = Scanner;
39+
module.exports.Filters = Filters;
40+
41+
AppManager.EVENT = {
42+
CLOSE: "close",
43+
SIGUSR2: "SIGUSR2",
44+
SIGTERM: "SIGTERM",
45+
EXIT: "exit",
46+
SIGINT: "SIGINT",
47+
SIGUSR1: "SIGUSR1"
48+
};
49+
50+
function AppManager(config) {
51+
this.config = config;
52+
this.listeners = [];
53+
}
54+
55+
AppManager.prototype.init = function () {
56+
debug("init");
57+
58+
process.on('close', this._onClose.bind(this, AppManager.EVENT.CLOSE));
59+
process.on('SIGUSR1', this._onClose.bind(this, AppManager.EVENT.SIGUSR1));
60+
process.on('SIGUSR2', this._onClose.bind(this, AppManager.EVENT.SIGUSR2));
61+
process.on('SIGTERM', this._onClose.bind(this, AppManager.EVENT.SIGTERM));
62+
process.on('exit', this._onClose.bind(this, AppManager.EVENT.EXIT));
63+
process.on('SIGINT', this._onClose.bind(this, AppManager.EVENT.SIGINT));
64+
process.on('error', this._onError.bind(this));
65+
66+
this._collectListeners();
67+
68+
//sorting based on priority
69+
debug("sorting app listeners based on priority...");
70+
this.listeners.sort(this.priorityComparator);
71+
debug("sorted list of listeners : ", this.listeners);
72+
73+
this._preStart();
74+
};
75+
76+
AppManager.prototype._collectListeners = function () {
77+
debug("searching app listeners...");
78+
var c = {
79+
root: this.config.home,
80+
directoryFilter: this.config.directoryFilter || Filters.DirFilters.ExceptNodeModules,
81+
filesFilter: this.config.filesFilter || Filters.FileFilters.EndsWithAppListener
82+
}
83+
var files = new Scanner(c).getFiles();
84+
debug("found app listeners :", files);
85+
86+
this.listeners = [];
87+
debug("getting all listeners reference...");
88+
for (var i = 0; i < files.length; i++) {
89+
try {
90+
var _class = require(files[i]);
91+
if (_class instanceof AppListener) {
92+
this.listeners.push(_class);
93+
}
94+
} catch (e) {
95+
debug("error in require for : %s", files[i], e);
96+
}
97+
}
98+
debug("final list of app listeners :", this.listeners);
99+
};
100+
101+
//can be over-ride if required
102+
AppManager.prototype.priorityComparator = function (a, b) {
103+
return a.priority < b.priority;
104+
};
105+
106+
//internal
107+
AppManager.prototype._preStart = function () {
108+
debug("preStart");
109+
new ChainHandler(this.listeners, 'preStart', this._onStart.bind(this)).start();
110+
};
111+
112+
AppManager.prototype._onStart = function (err) {
113+
if (err != null) {
114+
console.error("appmanager:state preStart-failed", err);
115+
this._onError(err);
116+
process.exit(-1);
117+
}
118+
debug("onStart");
119+
new ChainHandler(this.listeners, 'onStart', this._postStart.bind(this)).start();
120+
};
121+
122+
AppManager.prototype._postStart = function (err) {
123+
if (err != null) {
124+
console.error("appmanager:state onStart-failed", err);
125+
this._onError(err);
126+
process.exit(-1);
127+
}
128+
debug("postStart");
129+
new ChainHandler(this.listeners, 'postStart', this._postStartCalled.bind(this)).start();
130+
};
131+
132+
AppManager.prototype._postStartCalled = function (err) {
133+
if (err != null) {
134+
console.error("appmanager:state postStart-failed", err);
135+
this._onError(err);
136+
process.exit(-1);
137+
}
138+
debug("postStart ended");
139+
};
140+
141+
AppManager.prototype._onClose = function (type, exitCode) {
142+
debug("close, event-type:%s, exit-code:%s", type, exitCode);
143+
this.listeners.forEach(function (obj) {
144+
try {
145+
obj.onClose(type, exitCode);
146+
} catch (e) {
147+
console.error("Error in Calling onClose for %s.onClose", obj.constructor.name);
148+
}
149+
});
150+
process.exit(0);
151+
};
152+
153+
AppManager.prototype._onError = function (err) {
154+
debug("error :", err);
155+
this.listeners.forEach(function (obj) {
156+
try {
157+
obj.onError(err);
158+
} catch (e) {
159+
console.error("Error in Calling onError for %s.onError", obj.constructor.name);
160+
}
161+
});
162+
};
163+

lib/ChainHandler.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2018 Vivek Kumar
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
module.exports = ChainHandler;
26+
27+
function ChainHandler(objectArray, functionName, onEndCallback) {
28+
this.timer = null;
29+
this.objectArray = objectArray;
30+
this.functionName = functionName;
31+
this.onEndCallback = onEndCallback;
32+
33+
if (objectArray == null || objectArray.length <= 0) {
34+
this.onEnd();
35+
return;
36+
}
37+
}
38+
39+
ChainHandler.prototype._getInfo = function (index) {
40+
return this.objectArray[index].constructor.name + "." + this.functionName;
41+
}
42+
43+
ChainHandler.prototype._getMethod = function (index) {
44+
return this.objectArray[index][this.functionName];
45+
}
46+
47+
ChainHandler.prototype.start = function () {
48+
this._callFunction(0);
49+
};
50+
51+
ChainHandler.prototype._callFunction = function (index) {
52+
var self = this;
53+
54+
this.timer = setInterval(function () {
55+
//checking for current function called next function or not
56+
console.error("appmanager:chain-handler Chain-Break-Error: next function is not called from : %s. Fix Your Code.", self._getInfo(index));
57+
}, 5000);
58+
59+
//calling users method, so handle safely
60+
try {
61+
self._getMethod(index)(function () {
62+
63+
//clearing current chain break error handling timer
64+
clearInterval(self.timer);
65+
66+
if (index < self.objectArray.length - 1) {
67+
//releasing current call stack before calling next chaining function
68+
process.nextTick(self._callFunction.bind(self), index + 1);
69+
} else {
70+
self.onEnd();
71+
}
72+
});
73+
} catch (e) {
74+
clearInterval(self.timer);
75+
self.onEnd(new Error("Exception in Calling Chain Method for " + self._getInfo(index), e));
76+
}
77+
};
78+
79+
ChainHandler.prototype.onEnd = function (err) {
80+
process.nextTick(this.onEndCallback, err);
81+
};

lib/Filters.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2018 Vivek Kumar
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
var Filters = {
26+
FileFilters: {
27+
StartsWithAppListener: function (file) {
28+
return file.startsWith("AppListener");
29+
},
30+
EndsWithAppListener: function (file) {
31+
return file.endsWith("AppListener.js");
32+
}
33+
},
34+
DirFilters: {
35+
ExceptNodeModules: function (dir_path) {
36+
return (dir_path.indexOf("/node_modules") < 0);
37+
}
38+
}
39+
};
40+
41+
module.exports = Filters;

0 commit comments

Comments
 (0)