-
-
Notifications
You must be signed in to change notification settings - Fork 762
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #115 from feathersjs/fix-duplicate-events
Fix duplicate events in dynamic services.
- Loading branch information
Showing
8 changed files
with
730 additions
and
760 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,105 @@ | ||
'use strict'; | ||
|
||
var _ = require('lodash'); | ||
var eventsMixin = require('../../mixins/event').Mixin; | ||
|
||
// The position of the params parameters for a service method so that we can extend them | ||
// default is 1 | ||
var paramsPositions = { | ||
exports.paramsPositions = { | ||
find: 0, | ||
update: 2, | ||
patch: 2 | ||
}; | ||
|
||
exports.addService = function addService(service, path){ | ||
// Add handlers for the service to connected sockets. | ||
_.each(this.info.connections, function (spark) { | ||
this.setupMethodHandlers(service, path, spark); | ||
}, this); | ||
// The default event dispatcher | ||
exports.defaultDispatcher = function (data, params, callback) { | ||
callback(null, data); | ||
}; | ||
|
||
// Set up event handlers for a given service using the event dispatching mechanism | ||
exports.setupEventHandlers = function (info, service, path) { | ||
// If the service emits events that we want to listen to (Event mixin) | ||
if (typeof service.on === 'function' && service._serviceEvents) { | ||
var addEvent = function (ev) { | ||
service.on(ev, function (data) { | ||
// Check if there is a method on the service with the same name as the event | ||
var dispatcher = typeof service[ev] === 'function' ? | ||
service[ev] : exports.defaultDispatcher; | ||
var eventName = path + ' ' + ev; | ||
|
||
info.clients().forEach(function (socket) { | ||
dispatcher(data, info.params(socket), function (error, dispatchData) { | ||
if (error) { | ||
socket[info.method]('error', error); | ||
} else if (dispatchData) { // Only dispatch if we have data | ||
socket[info.method](eventName, dispatchData); | ||
} | ||
}); | ||
}); | ||
}); | ||
}; | ||
|
||
// Setup events for the service. | ||
eventsMixin.applyEvents.call(service); | ||
exports.setupEventHandlers.call(this, service, path); | ||
_.each(service._serviceEvents, addEvent); | ||
} | ||
}; | ||
|
||
// Set up the service method handler for a service and socket. | ||
exports.setupMethodHandler = function setupMethodHandler(emitter, params, service, path, method) { | ||
var name = path + '::' + method; | ||
var position = typeof paramsPositions[method] !== 'undefined' ? paramsPositions[method] : 1; | ||
// Set up all method handlers for a service and socket. | ||
exports.setupMethodHandlers = function (info, socket, service, path) { | ||
this.methods.forEach(function (method) { | ||
if (typeof service[method] !== 'function') { | ||
return; | ||
} | ||
|
||
var name = path + '::' + method; | ||
var params = info.params(socket); | ||
var position = typeof exports.paramsPositions[method] !== 'undefined' ? | ||
exports.paramsPositions[method] : 1; | ||
|
||
if (typeof service[method] === 'function') { | ||
emitter.on(name, function () { | ||
socket.on(name, function () { | ||
var args = _.toArray(arguments); | ||
// If the service is called with no parameter object | ||
// insert an empty object | ||
if(typeof args[position] === 'function') { | ||
if (typeof args[position] === 'function') { | ||
args.splice(position, 0, {}); | ||
} | ||
args[position] = _.extend({ query: args[position] }, params); | ||
args[position] = _.extend({query: args[position]}, params); | ||
service[method].apply(service, args); | ||
}); | ||
} | ||
}); | ||
}; | ||
|
||
exports.setupEventHandlers = function setupEventHandlers(service, path){ | ||
// If the service emits events that we want to listen to (Event mixin) | ||
if (typeof service.on === 'function' && service._serviceEvents) { | ||
_.each(service._serviceEvents, function (ev) { | ||
exports.setupEventHandler(this.info, service, path, ev); | ||
}, this); | ||
} | ||
// Common setup functionality taking the info object which abstracts websocket access | ||
exports.setup = function (info) { | ||
var app = this; | ||
var setupEventHandlers = exports.setupEventHandlers.bind(this, info); | ||
|
||
app._commons = info; | ||
|
||
// For a new connection, set up the service method handlers | ||
info.connection().on('connection', function (socket) { | ||
var setupMethodHandlers = exports.setupMethodHandlers.bind(app, info, socket); | ||
// Process all registered services | ||
_.each(app.services, setupMethodHandlers); | ||
}); | ||
|
||
// Set up events and event dispatching | ||
_.each(app.services, setupEventHandlers); | ||
}; | ||
|
||
// Set up event handlers for a given service and connected sockets. | ||
// Send it through the service dispatching mechanism (`removed(data, params, callback)`, | ||
// `updated(data, params, callback)` and `created(data, params, callback)`) if it | ||
// exists. | ||
exports.setupEventHandler = function setupEventHandler (info, service, path, ev) { | ||
var defaultDispatcher = function (data, params, callback) { | ||
callback(null, data); | ||
}; | ||
|
||
service.on(ev, function (data) { | ||
// Check if there is a method on the service with the same name as the event | ||
var dispatcher = typeof service[ev] === 'function' ? service[ev] : defaultDispatcher; | ||
var eventName = path + ' ' + ev; | ||
|
||
info.emitters().forEach(function (emitter) { | ||
dispatcher(data, info.params(emitter), function (error, dispatchData) { | ||
if (error) { | ||
emitter[info.method]('error', error); | ||
} else if (dispatchData) { | ||
emitter[info.method](eventName, dispatchData); | ||
} | ||
}); | ||
// Socket mixin when a new service is registered | ||
exports.service = function (path, service) { | ||
var protoService = this._super.apply(this, arguments); | ||
var info = this._commons; | ||
|
||
// app._socketInfo will only be available once we are set up | ||
if (service && info) { | ||
var setupEventHandlers = exports.setupEventHandlers.bind(this, info); | ||
var setupMethodHandlers = exports.setupMethodHandlers.bind(this, info); | ||
|
||
// Set up event handlers for this new service | ||
setupEventHandlers(protoService, path); | ||
// For any existing connection add method handlers | ||
info.clients().forEach(function (socket) { | ||
setupMethodHandlers(socket, path, protoService); | ||
}); | ||
}); | ||
} | ||
|
||
return protoService; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.