support rfc2812-style LIST
[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
43 // Get an instance of the module and remove it from the cache
44 try {
45 module = require(module_file);
46 delete require.cache[require.resolve(module_file)];
47 } catch (err) {
48 // Module was not found
49 console.log(err);
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 registered_modules = _.reject(registered_modules, function (registered_module) {
60 if (module === registered_module) {
61 module.dispose();
62 return true;
63 }
64 });
65 }
66
67
68
69
70
71
72 /**
73 * Module object
74 * To be created by modules to bind to server events
75 */
76 function Module (module_name) {
77 registered_modules[module_name] = this;
78 }
79
80
81 // Holder for all the bound events by this module
82 Module.prototype._events = {};
83
84
85 // Keep track of this modules events and bind
86 Module.prototype.on = function (event_name, fn) {
87 var internal_events = ['dispose'];
88
89 this._events[event_name] = this._events[event_name] || [];
90 this._events[event_name].push(fn);
91
92 // If this is an internal event, do not propogate the event
93 if (internal_events.indexOf(event_name) === -1) {
94 active_publisher.on(event_name, fn);
95 }
96 };
97
98
99 // Keep track of this modules events and bind once
100 Module.prototype.once = function (event_name, fn) {
101 this._events[event_name] = this._events[event_name] || [];
102 this._events[event_name].push(fn);
103
104 active_publisher.once(event_name, fn);
105 };
106
107
108 // Remove any events by this module only
109 Module.prototype.off = function (event_name, fn) {
110 var idx;
111
112 if (typeof event_name === 'undefined') {
113 // Remove all events
114 this._events = [];
115
116 } else if (typeof fn === 'undefined') {
117 // Remove all of 1 event type
118 delete this._events[event_name];
119
120 } else {
121 // Remove a single event + callback
122 for (idx in (this._events[event_name] || [])) {
123 if (this._events[event_name][idx] === fn) {
124 delete this._events[event_name][idx];
125 }
126 }
127 }
128
129 active_publisher.removeListener(event_name, fn);
130 };
131
132
133
134 // Clean up anything used by this module
135 Module.prototype.dispose = function () {
136 // Call any dispose callbacks
137 (this._events['dispose'] || []).forEach(function (callback) {
138 callback();
139 });
140
141 // Remove all bound event listeners
142 this.off();
143 };
144
145
146
147
148
149
150 module.exports = {
151 // Objects
152 Module: Module,
153 Publisher: Publisher,
154
155 // Methods
156 registerPublisher: registerPublisher,
157 load: loadModule,
158 unload: unloadModule,
159 getRegisteredModules: function () { return registered_modules; }
160 };