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