Skip to content

Commit b07a368

Browse files
joseph-onsipWill Mitchell
authored andcommitted
EventEmitter: inherit from Node's EventEmitter
This reduces code duplication by using a well known/tested module: http://nodejs.org/api/events.html This also preserves most of the public API: http://sipjs.com/api/0.6.0/eventEmitter/ See below for more details: * #on, #once and #off do NOT take third arguments (bindTarget) listeners should be explicitly bound to their objects before passing to EventEmitter methods * #setMaxListeners works like Node's - does NOT prevent extra listeners - passing 0 allows unlimited listeners * #emit no longer returns `this`, works like Node's * #checkListener has been removed The rest of SIP.js uses: emitter.listeners(eventName).length instead of: emitter.checkListener(eventName) * remove all other methods and their tests Supporting changes: * test/spec/SpecSession.js: define .logger on the constructed Session This prevents tests from failing due to an artificially constructed Session's logger being undefined since the Session no longer has a logger by virtue of being an EventEmitter * src/Session.js: fix the following methods to correctly return `this`: - failed - rejected - canceled - accepted - terminated - connecting
1 parent 1e52916 commit b07a368

23 files changed

+85
-640
lines changed

src/ClientContext.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,7 @@ module.exports = function (SIP) {
33
var ClientContext;
44

55
ClientContext = function (ua, method, target, options) {
6-
var originalTarget = target,
7-
events = [
8-
'progress',
9-
'accepted',
10-
'rejected',
11-
'failed',
12-
'cancel'
13-
];
6+
var originalTarget = target;
147

158
// Validate arguments
169
if (target === undefined) {
@@ -54,7 +47,6 @@ ClientContext = function (ua, method, target, options) {
5447
this.localIdentity = this.request.from;
5548
this.remoteIdentity = this.request.to;
5649

57-
this.initEvents(events);
5850
this.data = {};
5951
};
6052
ClientContext.prototype = new SIP.EventEmitter();

src/Dialogs.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ Dialog = function(owner, message, type, state) {
9292
this.owner = owner;
9393
owner.ua.dialogs[this.id.toString()] = this;
9494
this.logger.log('new ' + type + ' dialog created with status ' + (this.state === C.STATUS_EARLY ? 'EARLY': 'CONFIRMED'));
95-
owner.initMoreEvents(['dialog']);
9695
owner.emit('dialog', this);
9796
};
9897

src/EventEmitter.js

Lines changed: 9 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,16 @@
11
"use strict";
2-
/**
3-
* @fileoverview EventEmitter
4-
*/
2+
var NodeEventEmitter = require('events').EventEmitter;
53

6-
/**
7-
* @augments SIP
8-
* @class Class creating an event emitter.
9-
*/
10-
module.exports = function (SIP) {
11-
var
12-
EventEmitter,
13-
logger = new SIP.LoggerFactory().getLogger('sip.eventemitter'),
14-
C = {
15-
MAX_LISTENERS: 10
16-
};
4+
function EventEmitter () {}
175

18-
EventEmitter = function(){};
19-
EventEmitter.prototype = {
20-
/**
21-
* Initialize events dictionaries.
22-
* @param {Array} events
23-
*/
24-
initEvents: function(events) {
25-
this.events = {};
6+
EventEmitter.prototype = Object.create(NodeEventEmitter.prototype);
267

27-
return this.initMoreEvents(events);
28-
},
29-
30-
initMoreEvents: function(events) {
31-
var idx;
32-
33-
if (!this.logger) {
34-
this.logger = logger;
35-
}
36-
37-
this.maxListeners = C.MAX_LISTENERS;
38-
39-
for (idx = 0; idx < events.length; idx++) {
40-
if (!this.events[events[idx]]) {
41-
this.logger.log('adding event '+ events[idx]);
42-
this.events[events[idx]] = [];
43-
} else {
44-
this.logger.log('skipping event '+ events[idx]+ ' - Event exists');
45-
}
46-
}
47-
48-
return this;
49-
},
50-
51-
/**
52-
* Check whether an event exists or not.
53-
* @param {String} event
54-
* @returns {Boolean}
55-
*/
56-
checkEvent: function(event) {
57-
return !!(this.events && this.events[event]);
58-
},
59-
60-
/**
61-
* Check whether an event exists and has at least one listener or not.
62-
* @param {String} event
63-
* @returns {Boolean}
64-
*/
65-
checkListener: function(event) {
66-
return this.checkEvent(event) && this.events[event].length > 0;
67-
},
68-
69-
/**
70-
* Add a listener to the end of the listeners array for the specified event.
71-
* @param {String} event
72-
* @param {Function} listener
73-
*/
74-
on: function(event, listener, bindTarget) {
75-
if (listener === undefined) {
76-
return this;
77-
} else if (typeof listener !== 'function') {
78-
this.logger.error('listener must be a function');
79-
return this;
80-
} else if (!this.checkEvent(event)) {
81-
this.logger.error('unable to add a listener to a nonexistent event '+ event);
82-
throw new TypeError('Invalid or uninitialized event: ' + event);
83-
}
84-
85-
var listenerObj = { listener: listener };
86-
if (bindTarget) {
87-
listenerObj.bindTarget = bindTarget;
88-
}
89-
90-
if (this.events[event].length >= this.maxListeners) {
91-
this.logger.warn('max listeners exceeded for event '+ event);
92-
return this;
93-
}
94-
95-
this.events[event].push(listenerObj);
96-
this.logger.log('new listener added to event '+ event);
97-
return this;
98-
},
99-
100-
/**
101-
* Add a one time listener for the specified event.
102-
* The listener is invoked only the next time the event is fired, then it is removed.
103-
* @param {String} event
104-
* @param {Function} listener
105-
*/
106-
once: function(event, listener, bindTarget) {
107-
var self = this;
108-
function listenOnce () {
109-
/* jshint validthis:true */
110-
listener.apply(this, arguments);
111-
self.off(event, listenOnce, bindTarget);
112-
}
113-
114-
return this.on(event, listenOnce, bindTarget);
115-
},
116-
117-
/**
118-
* Remove a listener from the listener array for the specified event.
119-
* Note that the order of the array elements will change after removing the listener
120-
* @param {String} event
121-
* @param {Function} listener
122-
*/
123-
off: function(event, listener, bindTarget) {
124-
var events, length,
125-
idx = 0;
126-
127-
if (listener && typeof listener !== 'function') {
128-
this.logger.error('listener must be a function');
129-
return this;
130-
} else if (!event) {
131-
for (idx in this.events) {
132-
this.events[idx] = [];
133-
}
134-
return this;
135-
} else if (!this.checkEvent(event)) {
136-
this.logger.error('unable to remove a listener from a nonexistent event '+ event);
137-
throw new TypeError('Invalid or uninitialized event: ' + event);
138-
}
139-
140-
events = this.events[event];
141-
length = events.length;
142-
143-
while (idx < length) {
144-
if (events[idx] &&
145-
(!listener || events[idx].listener === listener) &&
146-
(!bindTarget || events[idx].bindTarget === bindTarget)) {
147-
events.splice(idx,1);
148-
} else {
149-
idx ++;
150-
}
151-
}
152-
153-
return this;
154-
},
155-
156-
/**
157-
* By default EventEmitter will print a warning
158-
* if more than C.MAX_LISTENERS listeners are added for a particular event.
159-
* This function allows that limit to be modified.
160-
* @param {Number} listeners
161-
*/
162-
setMaxListeners: function(listeners) {
163-
if (typeof listeners !== 'number' || listeners < 0) {
164-
this.logger.error('listeners must be a positive number');
165-
return this;
166-
}
167-
168-
this.maxListeners = listeners;
169-
return this;
170-
},
171-
172-
/**
173-
* Execute each of the listeners in order with the supplied arguments.
174-
* @param {String} events
175-
* @param {Array} args
176-
*/
177-
emit: function(event) {
178-
if (!this.checkEvent(event)) {
179-
this.logger.error('unable to emit a nonexistent event '+ event);
180-
throw new TypeError('Invalid or uninitialized event: ' + event);
181-
}
182-
183-
this.logger.log('emitting event '+ event);
184-
185-
// Fire event listeners
186-
var args = Array.prototype.slice.call(arguments, 1);
187-
this.events[event].slice().forEach(function (listener) {
188-
try {
189-
listener.listener.apply(listener.bindTarget || this, args);
190-
} catch(err) {
191-
this.logger.error(err.stack);
192-
}
193-
}, this);
194-
195-
return this;
8+
EventEmitter.prototype.off = function off (eventName, listener) {
9+
if (arguments.length < 2) {
10+
return this.removeAllListeners.apply(this, arguments);
11+
} else {
12+
return this.removeListener(eventName, listener);
19613
}
19714
};
19815

199-
EventEmitter.C = C;
200-
201-
SIP.EventEmitter = EventEmitter;
202-
};
16+
module.exports = EventEmitter;

src/RegisterContext.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@ var RegisterContext;
55

66
RegisterContext = function (ua) {
77
var params = {},
8-
regId = 1,
9-
events = [
10-
'registered',
11-
'unregistered'
12-
];
8+
regId = 1;
139

1410
this.registrar = ua.configuration.registrarServer;
1511
this.expires = ua.configuration.registerExpires;
@@ -43,7 +39,6 @@ RegisterContext = function (ua) {
4339
this.registered = false;
4440

4541
this.logger = ua.getLogger('sip.registercontext');
46-
this.initMoreEvents(events);
4742
};
4843

4944
RegisterContext.prototype = {

src/SIP.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Object.defineProperties(SIP, {
2020

2121
require('./Utils')(SIP, environment);
2222
SIP.LoggerFactory = require('./LoggerFactory')(environment.console);
23-
require('./EventEmitter')(SIP);
23+
SIP.EventEmitter = require('./EventEmitter');
2424
SIP.C = require('./Constants')(SIP.name, SIP.version);
2525
SIP.Exceptions = require('./Exceptions');
2626
SIP.Timers = require('./Timers')(environment.timers);

src/ServerContext.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ module.exports = function (SIP) {
33
var ServerContext;
44

55
ServerContext = function (ua, request) {
6-
var events = [
7-
'progress',
8-
'accepted',
9-
'rejected',
10-
'failed'
11-
];
126
this.ua = ua;
137
this.logger = ua.getLogger('sip.servercontext');
148
this.request = request;
@@ -30,8 +24,6 @@ ServerContext = function (ua, request) {
3024

3125
this.localIdentity = request.to;
3226
this.remoteIdentity = request.from;
33-
34-
this.initEvents(events);
3527
};
3628

3729
ServerContext.prototype = new SIP.EventEmitter();

0 commit comments

Comments
 (0)