Log client startup errors to console
[KiwiIRC.git] / server / modules.js
1 var events = require('events'),
2 util = require('util'),
3 path = require('path'),
4 _ = require('lodash'),
5 EventPublisher = require('./plugininterface.js');
6
7
8 /**
9 * Publisher
10 * The main point in which events are fired and bound to
11 */
12
13 // Where events are bound to
14 var active_publisher;
15
16
17 // Create a publisher to allow event subscribing
18 function Publisher (obj) {
19 var EventPublisher = require('./plugininterface.js');
20 return new EventPublisher();
21 }
22
23
24 // Register an already created Publisher() as the active instance
25 function registerPublisher (obj) {
26 active_publisher = obj;
27 }
28
29
30
31
32
33
34 /**
35 * Keeping track of modules
36 */
37
38 // Hold the loaded modules
39 var registered_modules = [];
40
41 function loadModule (module_file) {
42 var module,
43 full_module_filename = path.join(global.config.module_dir, module_file);
44
45 // Make sure that the module is contained in the proper module directory
46 if (full_module_filename.lastIndexOf(global.config.module_dir, 0) !== 0) {
47 return false;
48 }
49
50 // Get an instance of the module and remove it from the cache
51 try {
52 module = require(full_module_filename);
53 delete require.cache[require.resolve(full_module_filename)];
54 } catch (err) {
55 // Module was not found
56 return false;
57 }
58
59 return module;
60 }
61
62
63 // Find a registered collection, .dispose() of it and remove it
64 function unloadModule (module) {
65 var found_module = false;
66
67 registered_modules = _.reject(registered_modules, function (registered_module) {
68 if (module.toLowerCase() === registered_module.module_name.toLowerCase()) {
69 found_module = true;
70
71 registered_module.dispose();
72 return true;
73 }
74 });
75
76 return found_module;
77 }
78
79
80
81
82
83
84 /**
85 * Module object
86 * To be created by modules to bind to server events
87 */
88 function Module (module_name) {
89 registered_modules.push(this);
90 this.module_name = module_name;
91
92 // Holder for all the bound events by this module
93 this._events = {};
94 }
95
96
97
98 // Keep track of this modules events and bind
99 Module.prototype.on = function (event_name, fn) {
100 var internal_events = ['dispose'];
101
102 this._events[event_name] = this._events[event_name] || [];
103 this._events[event_name].push(fn);
104
105 // If this is an internal event, do not propogate the event
106 if (internal_events.indexOf(event_name) === -1) {
107 active_publisher.on(event_name, fn);
108 }
109 };
110
111
112 // Keep track of this modules events and bind once
113 Module.prototype.once = function (event_name, fn) {
114 this._events[event_name] = this._events[event_name] || [];
115 this._events[event_name].push(fn);
116
117 active_publisher.once(event_name, fn);
118 };
119
120
121 // Remove any events by this module only
122 Module.prototype.off = function (event_name, fn) {
123 var idx;
124
125 if (typeof event_name === 'undefined') {
126 // Remove all events
127 this._events = [];
128
129 } else if (typeof fn === 'undefined') {
130 // Remove all of 1 event type
131 delete this._events[event_name];
132
133 } else {
134 // Remove a single event + callback
135 for (idx in (this._events[event_name] || [])) {
136 if (this._events[event_name][idx] === fn) {
137 delete this._events[event_name][idx];
138 }
139 }
140 }
141
142 active_publisher.off(event_name, fn);
143 };
144
145
146
147 // Clean up anything used by this module
148 Module.prototype.dispose = function () {
149 // Call any dispose callbacks
150 (this._events['dispose'] || []).forEach(function (callback) {
151 callback();
152 });
153
154 // Remove all bound event listeners
155 this.off();
156 };
157
158
159
160
161
162
163 module.exports = {
164 // Objects
165 Module: Module,
166 Publisher: Publisher,
167
168 // Methods
169 registerPublisher: registerPublisher,
170 load: loadModule,
171 unload: unloadModule,
172 getRegisteredModules: function () { return registered_modules; }
173 };