Node.js + Socket.io Storing data in sockets - node.js

I am currently building an application using node.js and using the socket.io module. When a user connects I am storing data specific to the user against their socket. For example
io.sockets.on('connection', function (socket) {
socket.on('sendmessage', function (data, type) {
socket.variable1 = 'some value';
socket.variable2 = 'Another value';
socket.variable3 = 'Yet another value';
});
});
While this works my question is, is this a good way to do it. I am effectively storing session data but is there a better way to do it?

I think that you should store those variables in another type of object. Keep the socket object only for the communication. You may generate an unique id for every user and create a map. Something like this:
var map = {},
numOfUsers = 0;
io.sockets.on('connection', function (socket) {
numOfUsers += 1;
var user = map["user" + numOfUsers] = {};
socket.on('sendmessage', function (data, type) {
user.variable1 = 'some value';
user.variable2 = 'Another value';
user.variable3 = 'Yet another value';
});
});

Update: io.set() and io.get() methods are deprecated
A reasonable way is to choose a data store and associate each data with a unique socket identifier (id, for example).
A recommended way is to use the native socket.set and socket.get to set and get data asynchronously specifically to the current socket.
Following your example:
io.sockets.on('connection', function (socket) {
socket.on('sendmessage', function (data, type) {
socket.set('variable1', 'some value');
socket.set('variable2', 'Another value');
socket.set('variable3', 'Yet another value');
});
});
Also, you can call a function asynchronously after you set a value:
...
socket.set('variable1', 'some value', function () {
/* something to be done after "variable1" is set */
});
...
Finally, you can retrieve a variable doing:
...
var variable1 = socket.get('variable1')
...
Or use it directly when needed:
if ( socket.get('age') > 30 ) {
// Vida longa às eleições presidenciais diretas no Brasil
}

Related

how to access a child node firebase nodejs

hello I have a data like this in my firebase database
I want to access the sender name.
Here is my code
var ref = firebase.database().ref().child('chat');
ref.on("child_added", function(data, prevChildKey) {
var newPlayer = data.val();
var key = data.key;
console.log(key);
});
data.key gives me the key 1-5. I want to access the value for example which is sender_name under 1-5. I don't know how can I do that. I have done something like this
var newPlayer = data.val();
console.log(newPlayer[key]['sender_name'];
But I got an undefined error
Child elements of chat node are 1-5, 6-10, etc. keys, not chat items, based on the data structure you show.
Firebase child_added event is only fired on direct children.
If you wish to listen to new items with child_added listener, you can:
Listen on each chat/1-5, chat/6-10, etc, for added children, but I understand this is not very convenient
Example to always listen to 1-5 children:
var ref = firebase.database().ref().child('chat/1-5');
ref.on("child_added", function(data) {
var item = data.val();
console.log('New message', item['sender_name'], item.text);
});
And a generic solution if you don't know what is the first key but you know it starts with '1-':
var ref = firebase.database().ref().child('chat');
var firstKey = null
ref.on("child_added", function(data) {
// If first key is what you are looking for
// and changed (or is null) update item listener
if (data.key.startsWith('1-') && data.key !== firstKey) {
// But first remove previous listener if present
firstKey && ref.child(firstKey).off("child_added", checkItemsAdded)
firstKey = data.key
ref.child(firstKey).on("child_added", checkItemsAdded)
}
});
function checkItemsAdded(data) {
var item = data.val();
console.log('New message', item['sender_name'], item.text);
}
And even more generic, listen to all intermediary keys (if you don't know what they are):
var ref = firebase.database().ref().child('chat');
ref.on("child_added", function(data) {
// function checkItemsAdded is the same as above
ref.child(firstKey).on("child_added", checkItemsAdded)
});
Note that this code listens to all sub keys like 1-5, etc. So if there are just a few, or a few dozen, I would say it is OK, but I would not advise to scale this above a few hundreds.
Other (recommended) option:
Change data structure in a way that all items are directly written as chat direct children. (Remove 1-5, 6-10 level)
As #Pandaiolo explains, the child_added events fires for direct children of the location you listen to. For each child it gives you a snapshot of all data under that child. So your data parameter contains all the information you're looking for. You just need to loop over it, to get one level deeper into the JSON with:
var ref = firebase.database().ref().child('chat');
ref.on("child_added", function(data, prevChildKey) {
var newPlayer = data.val();
console.log(data.key);
data.forEach(function(child) {
console.log(child.key, child.child("sender_name").val());
});
});
This will print all sender names.

Passing a return from one function to another function that already has set parameters?

Edit: I know JS is asynchronous, I have looked over the How to Return thread. The issue I'm having is that going from "foo" examples to something specific = I'm not quite sure where to re-format this.
Also here is some context: https://github.com/sharkwheels/beanballs/blob/master/bean-to-osc-two.js
I have a question about returns in node. It might be a dumb question, but here goes. I have a function that connects to a socket, and gets OSC messages from processing:
var sock = dgram.createSocket("udp4", function(msg, rinfo) {
try {
// get at all that info being sent out from Processing.
//console.log(osc.fromBuffer(msg));
var getMsg = osc.fromBuffer(msg);
var isMsg = getMsg.args[0].value;
var isName = getMsg.args[1].value;
var isAdd = getMsg.address;
var isType = getMsg.oscType;
// make an array out of it
var isAll = [];
isAll.push(isName);
isAll.push(isMsg);
isAll.push(isAdd);
isAll.push(isType);
// return the array
console.log(isAll);
return isAll;
} catch (error) {
console.log(error);
}
});
Below I have the start of another function, to write some of that array to a BLE device. It needs name and characteristics from a different function. How do I get the below function to use isAll AND two existing parameters?
var writeToChars = function (name, characteristics) { // this is passing values from the BLE setup function
// i need to get isAll to here.
// eventually this will write some values from isAll into a scratch bank.
}
Thanks.
async call in this case be written something like this. state can be maintained in the variables in closure if required. In this particular case - you can do without any state (isAll) as well.
var isAll;
var soc = dgram.createSocket('udp4', oncreatesocket);
function oncreatesocket(msg, rinfo)
{
isAll = parseMessage(msg);
writeData(isAll);
}
function parseMessage(msg) {
...
// code to parse msg and return isAll
}
function writeData() {}
if the writeData is small enough function. It can be inside oncreatesocket without impacting the readability of the code.
Alright. So I figured out what to do, at least in this scenario. I'm sure there is a better way to do this, but for now, this works.
I'm mapping an existing global array of peripherals into the write function, while passing the OSC message to it as a parameter. This solved my issue of "how do I get two pieces of information to the same place". It figures out which peripheral is which and writes a different value to each scratch bank of each peripheral accordingly. Leaving here for future reference.
var writeToBean = function(passThrough){
var passThrough = passThrough;
console.log("in Write to bean: ", passThrough);
_.map(beanArray, function(n){
if(n.advertisement.localName === passThrough.name){
//var name = n.advertisement.localName;
n.discoverSomeServicesAndCharacteristics(['a495ff20c5b14b44b5121370f02d74de'], [scratchThr], function(error, services, characteristics){
var service = services[0];
var characteristic = characteristics[0];
var toSend = passThrough.msg;
console.log("service", service);
console.log("characteristic", characteristic);
if (toSend != null) {
characteristic.write(new Buffer([toSend]), false, function(error) {
if (error) { console.log(error); }
console.log("wrote " + toSend + " to scratch bank 3");
});
}
// not sure how to make the program resume, it stops here. No error, just stops processing.
});
}
});
}

i have already tried,but i don't no how to call the function in another file

sir/madam exlain the flow of node.js from client to server with the dynamic parameters passing from userinterface to api's based up on these parameters we will get the output from api.for example sabre api etc..
exports.flightDestinations = function(req, res) {
var callback = function(error, data) {
if (error) {
// Your error handling here
console.log(error);
} else {
// Your success handling here
// console.log(JSON.parse(data));
res.send(JSON.parse(data));
}
};
sabre_dev_studio_flight.airports_top_destinations_lookup({
topdestinations: '50'
}, callback);
};
we want this value 50 from user...and how to give this value?and how to call this function in node.js.
The exports variable is initially set to that same object (i.e. it's a shorthand "alias"), so in the module code you would usually write something like this:
var myFunc1 = function() { ... };
var myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;
to export (or "expose") the internally scoped functions myFunc1 and myFunc2.
And in the calling code you would use:
var m = require('mymodule');
m.myFunc1();
where the last line shows how the result of require is (usually) just a plain object whose properties may be accessed.
NB: if you overwrite exports then it will no longer refer to module.exports. So if you wish to assign a new object (or a function reference) to exports then you should also assign that new object to module.exports
It's worth noting that the name added to the exports object does not have to be the same as the module's internally scoped name for the value that you're adding, so you could have:
var myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required
followed by:
var m = require('mymodule');
m.shortName(); // invokes module.myVeryLongInternalName

Pusher: How to bind to 100s of events?

The push library works as below
var channel = pusher.subscribe('test_channel');
channel.bind('my_event', function(data) {
alert(data.message);
});
However:
Would I be able to do this?
var channel = pusher.subscribe('test_channel');
channel.bind(['my_event1', 'my_event2'....'my_event100'], function(data) {
alert(data.message);
});
In my use case, I have one channel and there are many different events and each client might want to simulantaneously subscribe to 100s of events.
The signature for the channel.bind function is String channelName, Function callback (pusher-js source). You can't pass in an Array of channels`.
If you want the same function to be called then you'll need to pass a reference to the function and call bind multiple times:
var channel = pusher.subscribe('test_channel');
var callback = function(data) {
alert(data.message);
};
var eventName;
for( var i = 0; i < 100; ++i ) {
eventName = 'my_event' + ( i + 1 );
channel.bind( eventName, callback );
}
The single-threaded nature of JS will equate to these event binding happening simultaneously.
You could of course create your own helper function to allow bind( Array eventNames, Function callback ).

Get a collection and add a value to the response

I want to create in the Server script a function that can return a collection plus some extra value.
For example:
Meteor.publish("users", function () {
var users;
users = Meteor.users.find();
users.forEach(function (user){
user.profile.image = "some-url";
});
return users;
});
But this don't work proper. My question is: What is the right way to add a value to a collection reponse in a publish function.
There are 2 ways you can implement a publish function:
By returning a cursor (or an array of cursors)
By using this.added(), this.changed() and this.removed().
Only method 2 allows to modify returned documents.
Please refer to Meteor documentation here. However, since the provided sample code might look complex, here is another one:
// server: publish the rooms collection
Meteor.publish("rooms", function () {
return Rooms.find({});
});
is equivalent to:
// server: publish the rooms collection
Meteor.publish("rooms", function () {
var self = this;
var handle = Rooms.find({}).observeChanges({
added: function(id, fields) { self.added("rooms", id, fields); },
changed: function(id, fields) { self.changed("rooms", id, fields); },
removed: function(id) { self.added("rooms", id); },
}
});
self.ready();
self.onStop(function () { handle.stop(); });
});
In the second sample, you can modify the 'field' parameter before sending it for publication, like this:
added: function(id, fields) {
fields.newField = 12;
self.added("rooms", id, fields);
},
Source: this post.
Is this important to do with the server? You could use the transform function on the client:
Client JS
//Somewhere where it can run before anything else (make sure you have access to the other bits of the document i.e services.facebook.id otherwise you'll get a services is undefined
Meteor.users._transform = function(doc) {
doc.profile.image = "http://graph.facebook.com/" + doc.services.facebook.id + "/picture";
return doc;
}
Now when you do:
Meteor.user().profile.image
=> "http://graph.facebook.com/55592/picture"
I have opened an issue before with regards to sharing a transform onto the client: https://github.com/meteor/meteor/issues/821

Resources