Implementing listeners in Pusher when all there is to work with is bindings? - pusher

I'm trying to create a modular application in javascript using pusher. Different modules need to bind to the same pusher event and sometimes that event is nested in another event. Furthermore, these modules get loaded at different times depending on DOM events triggered by the user.
So, if one module has some code like
env.pusher.connection.bind('connected', function() {
env.my_channel.bind('private_message',function(data){ ... }
}
And another module comes along and wants to listen to the same private_message event. What happens if I write the same code is that the first bind gets overwritten.
What I'm looking for is a way to implement some kind of listeners, possibly with the option of removing a listener from a channel event.

I've thought of a solution myself. It comprises of the following steps:
keep a dictionary of pusher events
every module that wants to make use of a pusher event should search the dictionary first to see if that event exists and if not, write the code that creates the bind for the first time and add it to the dictionary
when a module creates the bind for the first time, it should also trigger a custom event and pass to it the data that pusher sends at the completion of the pusher event
every module that wants to make use of a pusher event should add a handler to the custom event that is triggered when the pusher event is triggered
If that looks hard to follow, here's some code inside a module that is a rewrite of the code in my question(I've used jQuery because jQuery is succint and has custom events already implemented):
if (typeof(env.pusher_events['my_channel']['private_message']) == 'undefined'){
env.pusher_events['my_channel']['private_message'] = true;
// 'pusher-connected' is defined in another module
// this module depends on that event but for brevity
// I'm not defining the 'connected' event here
$(document).on('pusher-connected', 'body', function(){
env.my_channel.bind('private_message', function(data){
$('body').trigger('pusher-my_channel-private_message', data);
})
})
}
$(document).on('pusher-my_channel-private_message', 'body', function(data){
// do something useful with the data
}
Would love to get some feedback on this (drawbacks etc.)

Related

How to iterate on each record of a Model.stream waterline query?

I need to do something like:
Lineup.stream({foo:"bar"}).exec(function(err,lineup){
// Do something with each record
});
Lineup is a collection with over 18000 records so I think using find is not a good option. What's the correct way to do this? From docs I can't figure out how to.
The .stream() method returns a node stream interface ( a read stream ) that emits events as data is read. Your options here are either to .pipe() to something else that can take "stream" input, such as the response object of the server, or to attach an event listener to the events emitted from the stream. i.e:
Piped to response
Lineup.stream({foo:"bar"}).pipe(res);
Setup event listeners
var stream = Lineup.stream({foo:"bar"});
stream.on("data",function(data) {
stream.pause(); // stop emitting events for a moment
/*
* Do things
*/
stream.resume(); // resume events
});
stream.on("err",function(err) {
// handle any errors that will throw in reading here
});
The .pause() and .resume() are quite inportant as otherwise things within the processing just keep responding to emitted events before that code is complete. While fine for small cases, this is not desirable for larger "streams" that the interface is meant to be used for.
Additionally, if you are calling any "asynchronous" actions inside the event handler like this, then you need to take care to .resume() within the callback or promise resolution , thus waiting for that "async" action to complete itself.
But look at the "node documentation" linked earlier for more in depth information on "stream".
P.S I believe the following syntax should also be supported if it suits your sensibilities better:
var stream = Lineup.find({foo:"bar"}).stream();

how to remove listener from inside the callback function in node.js

I set up a listener for an event emitter and what I want to do is to remove the same listener if I get certain events. The problem I am running into is that I don't know how to pass the callback function to removeListener inside the callback function. I tried "this", but it errors out. Is there any ways to achieve this? By the way, I am not using once because I am only removing the listener on a certain event.
P.S. I am using redis here so whatever message I receive I would always be listening on the key "message". It would not be possible to just listen on different keys. Channel wouldn't help either because I only want to remove a specific listener.
Also, what I want to do is communication between two completely independent process. No hierarchy of any kind. In process B, there are many independent functions that will get data from process A. My initial thought was using a message queue, but with that I cannot think of a way to ensure that each function in B will get the right data from A.
One cool thing about closures is that you can assign them a name, and that name can be used internally by the function. I haven't tested this, but you should try:
object.on('event', function handler() {
// do stuff
object.off('event', handler);
});
You should also look into whether your event emitter supports namespaces. That would let you do something like:
object.on('event.namespace', function() {
// do stuff
object.off('.namespace');
});

Is it possible to include the originator on a trigger?

As per the docs, client events are not delivered to the originator of an event. Is it possible to change this behaviour so that 1 client can send an event and all clients (including the originator) receive it?
Thanks!
This isn't available natively as part of the pusher-js library. Normally the originator of the event would probably just call the function that handles the event after triggering it:
function doTrigger( data ) {
var triggered = pusherInstance.trigger( 'private-channelName', 'eventName', data );
if( triggered ) {
handleTriggeredEvent( data );
}
}
function handleTriggeredEvent( data ) {
// Update UI
}
Alternatively you could manipulate the pusher-js library and change the trigger method to also emit the event on the channel. That way the event originators event handler will also be invoked.
To be honest, this suggestion is probably going to be a bit of a hack (you'd probably need to update the EventDispatcher object) so I think the earlier suggestions is the best solution.

view events are set twice when I instantiate view second time

This is my project architecture issue - its my first backbone project and I probably did something wrong.
In all my project in route callbacks I have:
myroute: function() {
this.currentView = new MyCustomView();
},
mysecondroute: function() {
this.currentView = new MySecondView()
},
//...
So in all route callbacks I instantiate some view. This view has initialze method which calls render method. It works except that all view events (declared in events: {}) are 'binded' every time same view is instantiated. so when I visit same route twice events for view corresponding to this route are fired twice...
Probably I shouldn instantiate new view on every route call - but how I can do this ? I mean what are the standards? Maybe I should just unload current view somehow - is there any method to do this?
I think you have to add a method to unbind all the events at the time to close the view
like this
close : function () {
//your code to clean everything before closing the view
this.remove();
this.unbind();
}
so the next time the view is called the events will be added during the initialization of the view, thats why you had events being called twice. the initialize method binds the events to the .el element. you need to make sure you unbind those at some point.

How to avoid the need to delay event emission to the next tick of the event loop?

I'm writing a Node.js application using a global event emitter. In other words, my application is built entirely around events. I find this kind of architecture working extremely well for me, with the exception of one side case which I will describe here.
Note that I do not think knowledge of Node.js is required to answer this question. Therefore I will try to keep it abstract.
Imagine the following situation:
A global event emitter (called mediator) allows individual modules to listen for application-wide events.
A HTTP Server is created, accepting incoming requests.
For each incoming request, an event emitter is created to deal with events specific to this request
An example (purely to illustrate this question) of an incoming request:
mediator.on('http.request', request, response, emitter) {
//deal with the new request here, e.g.:
response.send("Hello World.");
});
So far, so good. One can now extend this application by identifying the requested URL and emitting appropriate events:
mediator.on('http.request', request, response, emitter) {
//identify the requested URL
if (request.url === '/') {
emitter.emit('root');
}
else {
emitter.emit('404');
}
});
Following this one can write a module that will deal with a root request.
mediator.on('http.request', function(request, response, emitter) {
//when root is requested
emitter.once('root', function() {
response.send('Welcome to the frontpage.');
});
});
Seems fine, right? Actually, it is potentially broken code. The reason is that the line emitter.emit('root') may be executed before the line emitter.once('root', ...). The result is that the listener never gets executed.
One could deal with this specific situation by delaying the emission of the root event to the end of the event loop:
mediator.on('http.request', request, response, emitter) {
//identify the requested URL
if (request.url === '/') {
process.nextTick(function() {
emitter.emit('root');
});
}
else {
process.nextTick(function() {
emitter.emit('404');
});
}
});
The reason this works is because the emission is now delayed until the current event loop has finished, and therefore all listeners have been registered.
However, there are many issues with this approach:
one of the advantages of such event based architecture is that emitting modules do not need to know who is listening to their events. Therefore it should not be necessary to decide whether the event emission needs to be delayed, because one cannot know what is going to listen for the event and if it needs it to be delayed or not.
it significantly clutters and complexifies code (compare the two examples)
it probably worsens performance
As a consequence, my question is: how does one avoid the need to delay event emission to the next tick of the event loop, such as in the described situation?
Update 19-01-2013
An example illustrating why this behavior is useful: to allow a http request to be handled in parallel.
mediator.on('http.request', function(req, res) {
req.onceall('json.parsed', 'validated', 'methodoverridden', 'authenticated', function() {
//the request has now been validated, parsed as JSON, the kind of HTTP method has been overridden when requested to and it has been authenticated
});
});
If each event like json.parsed would emit the original request, then the above is not possible because each event is related to another request and you cannot listen for a combination of actions executed in parallel for a specific request.
Having both a mediator which listens for events and an emitter which also listens and triggers events seems overly complicated. I'm sure there is a legit reason but my suggestion is to simplify. We use a global eventBus in our nodejs service that does something similar. For this situation, I would emit a new event.
bus.on('http:request', function(req, res) {
if (req.url === '/')
bus.emit('ns:root', req, res);
else
bus.emit('404');
});
// note the use of namespace here to target specific subsystem
bus.once('ns:root', function(req, res) {
res.send('Welcome to the frontpage.');
});
It sounds like you're starting to run into some of the disadvantages of the observer pattern (as mentioned in many books/articles that describe this pattern). My solution is not ideal – assuming an ideal one exists – but:
If you can make a simplifying assumption that the event is emitted only 1 time per emitter (i.e. emitter.emit('root'); is called only once for any emitter instance), then perhaps you can write something that works like jQuery's $.ready() event.
In that case, subscribing to emitter.once('root', function() { ... }) will check whether 'root' was emitted already, and if so, will invoke the handler anyway. And if 'root' was not emitted yet, it'll defer to the normal, existing functionality.
That's all I got.
I think this architecture is in trouble, as you're doing sequential work (I/O) that requires definite order of actions but still plan to build app on components that naturally allow non-deterministic order of execution.
What you can do
Include context selector in mediator.on function e.g. in this way
mediator.on('http.request > root', function( .. ) { } )
Or define it as submediator
var submediator = mediator.yield('http.request > root');
submediator.on(function( ... ) {
emitter.once('root', ... )
});
This would trigger the callback only if root was emitted from http.request handler.
Another trickier way is to make background ordering, but it's not feasible with your current one mediator rules them all interface. Implement code so, that each .emit call does not actually send the event, but puts the produced event in list. Each .once puts consume event record in the same list. When all mediator.on callbacks have been executed, walk through the list, sort it by dependency order (e.g. if list has first consume 'root' and then produce 'root' swap them). Then execute consume handlers in order. If you run out of events, stop executing.
Oi, this seems like a very broken architecture for a few reasons:
How do you pass around request and response? It looks like you've got global references to them.
If I answer your question, you will turn your server into a pure synchronous function and you'd lose the power of async node.js. (Requests would be queued effectively, and could only start executing once the last request is 100% finished.)
To fix this:
Pass request & response to the emit() call as parameters. Now you don't need to force everything to run synchronously anymore, because when the next component handles the event, it will have a reference to the right request & response objects.
Learn about other common solutions that don't need a global mediator. Look at the pattern that Connect was based on many Internet-years ago: http://howtonode.org/connect-it <- describes middleware/onion routing

Resources