Custom Events in Node.js with Express framework - node.js

So, I'd like to know how to create custom events in node.js, and I'm hitting a wall. I'm pretty sure I'm misunderstanding something about how express works and how node.js events work.
https://creativespace.nodejitsu.com That's the app.
When a user creates a new "activity" (something that will happen many times) they send a POST request. Then within my route, if that POST succeeds I'd like to emit an event, that tells socket.io to create a new namespace for that activity.
In my route file:
var eventEmitter = require('events').EventEmitter;
// Tell socket.io about the new space.
eventEmitter.emit('new activity', {activityId: body.id});
And socket.io:
// When someone creates a new activity
eventEmitter.on('new activity', function (data) { // this gives and error
var newActivity = '/activity?' + data.activityId;
io.of(newActivity).on('connection', function (socket) {
// Socket.io code for an activity
});
});
So the error I get is CANNOT CALL METHOD ON OF UNDEFINED and it refers to what would be line 2 in the socket.io above. I think I'm messing up my requires, maybe...or I'm not quite understanding how events work.
Any help, even a reference to good reading on Node.js events would rock!
Thanks!!!

If using express you can also just listen for event on the express 'app' which inherits from EventEmitter. For example:
res.app.on("myEvent", function)
and emit to it like
res.app.emit("myEvent", data)

You should treat EventEmitter as a class you can inherit from. Try this:
function MyEmitter () {
events.EventEmitter.call(this);
}
util.inherits(MyEmitter, events.EventEmitter);
Now you can use your class to listen and emit events:
var e = new MyEmitter;
e.on("test", function (m) { console.log(m); });
e.emit("test", "Hello World!");

Related

Trigger function in app.js from module.js

First time poster — please forgive (and call me out) on any formatting mistakes!
So let's say I have app.js, which requires module.js. In module.js I have an express server running that can receive simple webrequests (GET / POST). Is there any way for me to trigger functions in app.js when I receive a request in module.js?
Something along the lines of:
var webModule = require('./module.js')
webModule.on('GET', async function (req) {
//do stuff with the request
});
The reason I'm not just putting the express server in app.js is that I want to run a certain amount of code to verify that the request is legitimate, and then re-use module.js in separate scripts to minimise the amount of code — and avoid having to update 5-6 scripts everytime I want to update the authentication process.
You can use the Event system that exists in Node.js. If you set it up correctly you can emit an event on each call and have a listener respond to the event.
Example from the Node.JS documentation:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
In your case you could create a class that extends EventEmitter that you use in each request. This class can then emit an event when the request gets call which is then handled in your app.js file by setting up the listener.
I might have a solution, will take some time to code (since my question is obviously very simplified).
In module.js:
var functionActions = {};
module.exports = {
on : (async function(requestType, returnFunction){
functionActions[requestType].do = returnFunction;
});
}
//general express code
app.get('*', function(req,res) {
if (verifyRequest(req) == 'okay'){ //authentication
return functionActions['GET'].do();
} else { //if the request is not authorised
res.status(403).send('Stop trying to hack me you stupid hacker ಠ╭╮ಠ');
}
});
I'll try it out and update this answer once I've figured out the potential kinks.

access data from this nodeJS function

I want to use "data" outside of this function. Please can some one show me how?
resemble('/Users/User/Documents/dev/engineerappcopy/VGimages/'+deviceName+'.png')
.compareTo('/Users/User/Documents/dev/engineerappcopy/VGimages/'+"nexUpdate"+'.png')
.ignoreColors().onComplete(function(data) {
browser.sleep(5000)
console.log(data);
data.getDiffImage().pack().
pipe(fs.createWriteStream('/Users/User/Documents/dev/engineerappcopy/VGimages/'+deviceName+'VG.png'));
});
I am aware that this is asynchronous, however I am struggling with this.
I would suggest you to use EventEmitters. You can use this if at all you want to indicate if any action is finished and optionally you can pass the data as well.
Create a new javscript file 'my-emitter.js'
my-emitter.js (ES6 version)
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
module.exports = myEmitter;
OR
my-emitter.js (Javascript version)
var EventEmitter = require('events').EventEmitter;
var util = require('util');
function MyEmitter(){
EventEmitter.call(this);
}
util.inherits(MyEmitter,EventEmitter);
myEmitter = new MyEmitter();
module.exports = myEmitter;
Your code snippet:
(Check the comments in the code). Emit an event saying that data is available after the async operation is complete
myEmitter.emit('img-op-complete',data);
var myEmitter = require('./my-emitter.js'); //Get your emitter from the module
resemble('/Users/User/Documents/dev/engineerappcopy/VGimages/'+deviceName+'.png')
.compareTo('/Users/User/Documents/dev/engineerappcopy/VGimages/'+"nexUpdate"+'.png')
.ignoreColors().onComplete(function(data) {
browser.sleep(5000)
//Emit the event that data is available and pass the data
myEmitter.emit('img-op-complete',data);
console.log(data);
data.getDiffImage().pack().
pipe(fs.createWriteStream('/Users/User/Documents/dev/engineerappcopy/VGimages/'+deviceName+'VG.png'));
});
othermodule.js
Where ever you want the data (if in other module), use the below piece of code
var myEmitter = require('./my-emitter.js'); //Get your emitter from the module
myEmitter.on('img-op-complete', function(data){
console.log(data); //You'll get your data here after op is done
})
Fore more info on events, https://nodejs.org/dist/latest-v6.x/docs/api/events.html
NOTE:
Promises is also nice solution, but if you use promises good design if data is needed within the same module. But events present a good design pattern in node.js
I would suggest go with promises, you would be able to use this promise across module also if you export it.
There are some really nice articles about how to use promises like Promise.
Coming to how to approach the above issue via promises,
function foo(){
return new Promise(function(resolve,reject){
resemble(<yourPath>)
.compareTo(<yourPath>)
.ignoreColors().onComplete(function(data) {
//for best practice do handle errors
if(err<anyError>){
reject(err);
} else{
resolve(data);
}
});
})
}
Now You can use the above promise where you want to use the data variable :
foo().then(function(<data>){
//do whatever you wish to do with the data
}).catch(function(<err>){
//handle the error
});

Asynchronous function with multiple emit events (futures in meteor)

My use case is to read RSS feed items asynchronously and load them into a meteor collection.
I have the feedparser npm module that does the parsing. It emits three events .on('error'), .on('meta') and .on('readable) with three different outputs.
When I run it in fixtures.js, with just console.log statements to run the output, its working fine.
When I use the same code to insert into a collection, I get errors related to asynchronocity of the function (assuming something to do with fibers)
So, I want to make it into a meteor method using futures as below -
http://www.discovermeteor.com/patterns/5828399
I tried but could not wrap my head around handling multiple events in Futures.
If you just want to push something to db at one point, it's enough to synchronize this call. Other than that, you can do whatever you want asynchronously. For example:
var Fiber = Npm.require('fibers');
var item = {};
var onInit = function() {
// do whatever with item
};
var onData = function() {
// do whatever with item
};
var onFinish = function() {
new Fiber(function(){
Documents.insert(item);
}).run();
};
Although Meteor is a great tool, I think node and its async insight is brilliant, and the best tool for what you are doing. Keep as a plan b having this part of your project be a straight node app.
Otherwise,
async from meteor
and

Events or functions on javascript class

I'm using EventEmitter in some classes, but i'm really confused whether event listening and events emitting are more efficient than calling object methods?
I want the object to be able to listen for a number of events that are emitted to it, and also emit a number of events to the object that originally emitted the events to the object and some others objects as well.
And i pretty much confused whether when should i use functions which in turn call other object methods and so on.
Events improve module decoupling. It is all about this simple question: "How many files do I have to touch to modify or add feature X?"
A simple example: You have a web server, a logging module and a starting script, which ties both together on startup. The function call way looks like this:
// Startup.js
var Startup = function() {
var logger = new Logger();
var server = new Server(logger);
};
// Logger.js
var Logger = function() {
};
Logger.prototype.log = function(msg) {
console.log(msg);
};
// Server.js
var Server = function(logger) {
this.logger = logger;
};
Server.prototype.start() {
this.logger.log("Start server...");
};
You can see that Startup knows all classes and Server knows about logger and how to use it. If I want to rename Logger's function log to write I have to touch Logger and Server.
Now let's have a look at a event driven approach:
// Startup.js
var Startup = function() {
var logger = new Logger();
var server = new Server();
server.addListener(logger);
};
// Logger.js
var Logger = function() {
this.on("startup", function(msg) {
console.log(msg);
});
};
Logger.prototype.__proto__ = EventEmitter.prototype;
// Server.js
var Server = function() {
};
Server.prototype.start() {
this.emit("startup", "Start server...");
};
Server.prototype.__proto__ = EventEmitter.prototype;
Now Logger and Server don't know each other. I can rename log and all I have to touch is Logger.js. I can even remove Logger or add more Loggers, all of them working with Server. But I never have to touch Server.js.
This is a simple example and decoupling doen't look important here. But the larger a project gets, the more benefits come up.
You can Unit-Test Server without having to mock Logger. And Logger is only one dependency. Imagine the advantage if Server had five or more submodules you have to simulate.
I hope this helps you to understand the benefits of event driven architectures.

Adding handlers to socket in loop doesnt work :/

To handle events send to socket in more orginased way, I've made a router. In that router I want to assign each module to specific event. I've assigned event strings and its handlers to "handlers" object. Then I wanted to assign listeners to given socket in a loop. After assignment I listed all events and it handlers in given socket to be clear. Everything seemd to be fine. Unfortunently, it doesnt work. Socket acts like it would assign every event in handlers object to first handler in that object. Handmade verion works fine, but I just cant get it why simple loop fails :/
Here is code of the socketio handling socket by router:
var socketOptions = {transports:['flashsocket', 'websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']};
var io = socketio.listen(server,socketOptions).on('connection', function (socket) {
streamRouter(io,socket);
});
And here is code of the router. I've wrote how looks handmade version of assigning sockets and how did look like looped verion. Normally, second one is commented.
var handlers = {
"message": require("./message").doAction,
"subscribe": require("./subscribe").doAction
}
exports.handleConnection = function(io,socket) {
//handmade version
socket.on("subscribe", function(msg){
require("./subscribe").doAction(io,socket,msg);
});
socket.on("message", function(msg){
require("./message").doAction(io,socket,msg);
});
//loop version
for( var event in handlers ) {
socket.on(event, function(msg){
handlers[event](io,socket,msg);
});
}
}
I'ld be greatful for any advice where the bug lies. In short time I'll have many handlers and assigning them one by one will be an ugly copying-pasting through many lines of code :/
In your for-in loop, you're constructing functions that are all closed over the same event variable. As a result, when those functions get executed, they will all refer to the same value. Additionally, you're not guarding your for-in loop against prototype members (which may or may not be intended).
Instead, try this:
Object.keys(handlers).forEach(function(event){
socket.on(event, function(msg){
handlers[event](io, socket, msg);
});
});
For your loop to work, you need to create a new scope for each handler:
for( var event in handlers ) {
(function(handler) {
socket.on(event, function(msg){
handler(io,socket,msg);
});
})(handlers[event]);
}
This has to do with scoping: Javascript doesn't create a 'new' event variable for each loop, and by the time the event handler is called, event will be overwritten (and will contain the value it had in the last iteration of the loop).
This page offers more explaination.

Resources