Tag Archives: socket.io

Meteor.js first impressions

Continue to write and learn server javascript. Recently I had a chance to read “Discover meteor” book and would like to share my first impressions about meteor.js

06637ff9d61e52470242fc6ce718ed3b

When I first knew about meteor.js from their promo video it looked fantastic. But I understood that it’s too young. Recently I’ve got an email that they launch stable 1.0 version. And they kindly provide their book(although for a limited time). So I didn’t miss opportunity to grab and read it.

Continue reading

Socket.io how rooms work. And another chat example.

I continue to learn nodejs and socket.io. Today I will explain how do socket.io rooms work. Since for me it’s was quite difficult to understand in details what is it and how it work.

And yes still I’m consider myself not a pro in nodejs and socket.io. So this articles addressed to developers who is also just started their node way.

Ok Go. If we look at socket.io rooms docs  we will find the info how to use rooms but there’s no way to understand HOW it works.

In fact it’s quite straightforward. But let’s see it in details. And we need start from io object. What is it?

var io = require('socket.io')(http);

io_dump_with_markers

As you see io keeps info about all connected sockets. This means that you can access socket object if you know it’s ID.

var socket = io.sockets.connected[socketId];

So every socket has it’s own ID. It is generated for each new socket. Now let’s look at socket instance connected to one room.

socket_dump_with_markers

As you see default socket ID automatically added to rooms.  Therefore when we need to send message to sockets in certain room…

io.sockets.to(chat.room).emit('message', {message: "details"});

(as I can assume) Socket.IO just go through the socket.rooms of the connected sockets and selects sockets that has specified room id. Easy? I think yes. But I must admit I spent some time to get this point.

I hope this could be useful. Also looking ahead I published another nodejs chat example using socket.io you can check it out. This could be a good start point to create your own chat with blackjack.

 

 

Socket IO authorization

I’d like to finish my story about my experiments with nodejs and socket.io. Check out my previous post http://radzserg.com/2014/07/01/socket-io-1-0-emitting-events-from-php/ .The last thing that I wanted to do is authorization. So imagine the following task we want to get updates for specific organization. My idea was quite simple in this case we can send authorization data (username:password or oauth token) to server plus send extra param like organization id

// let's add this param on frontend 
 var socket = io('http://localhost:8000', {
    query: "token=[oauth token]&organizationId=" + organizationId,
    transports: ['websocket']
});

Let’s add DB service that actually will perform authorization

var config = require('./src/config.json')
var pg = require('pg')
client = new pg.Client(config.pg.cdn);
client.connect(function (error) {
    if (error) {
        return console.error('could not connect to postgres', error);
    }
})

var dbService = require('./src/services/postgres_service.js')(client);

io.set('authorization', function (handshakeData, cb) {
    dbService.isUserAuthorized(handshakeData._query, function (result, error) {
        if (error) {
            return cb(error, false);
        }
        return cb(null, result);
    });
});

io.on('connection', function (socket) {
    // if we pass authorization join socket to organization room 
    socket.join("organization." + socket.request._query.organizationId);
});

An example of DB service could looks like this


module.exports = function (client) {

    return {
        isUserAuthorized: function (data, next) {
            var token = data.token ? data.token : null;
            if (!token) {
                return next(false, "Token must be specified");
            }
            var organizationId = data.organizationId ? data.organizationId : null;
            if (!organizationId) {
                return next(false, "organizationId must be specified");
            }

            var sql;
            sql = 'SELECT user_id FROM oauth_access_tokens WHERE access_token = $1 AND expires > NOW()';
            var query = client.query(sql, [token], function (error, result) {
                if (error) {
                    return next(false, error);
                }
                var userId = typeof result.rows[0] !== 'undefined' ? result.rows[0]['user_id'] : null;
                if (!userId) {
                    return next(false);
                }
                // then required queries to check if user has access to required organization. 
                // ... 
                return next(true)              
            });
        }
    }
};

Finally on PHP side we also can send events to specific room

$this->_emitter()->in("organization.{$orgnizationId}")->emit("news", [
     'data' => $data
]);

For now that’s it. Make a pause with nodejs. Although it was nice to play with it.

Simple node WAMP with redis pubsub

Tried to play with node. It’s always interesting to try something new.

My basic problem was to get new updates from redis queue using subscribe to channel. And pushing this message to client via websockets. I found http://socket.io/ and decide to use is as example.

Everything was brand new for me so today my story will be quite detailed.

Ok let’s go step by step.

1. Initiate our new project

  • mkdir wamptest
  • npm init (follow instructions)

2 Then as I mentioned I need some 3rd party libraries. Let’s add them

  • npm install redis –save
  • npm install socket.io –save

Here’s what I have in package.json

{
  "name": "radzserg-wamp-play",
  "description": "WAMP server toy project",
  "version": "0.0.1",
  "main": "server.js",
  "dependencies": {
    "redis": "^0.10.3",
    "socket.io": "0.8.x"
  },
  "private": "true"
}

Let’s finally start coding

We will use 2 files. Client and server. Client will be simple

index.html

Basically we set up socket connection and will just show what we got from server.

<html>
<head>
    <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
<!-- And yes we don't need to create this file. Node will do that for us. Some kind of magic that I didn't get at the beginning and was completely confused -->
    <script>
        $(function () {
            var socket = io.connect(null, {
                query: 'token=' + 123 + '&channelId=' + 1
            });
            socket.on('connect', function () {
                socket.on('message', function (message) {
                    console.log(message)
                    $('#messages').append($('<li></li>').text(message));
                });
                socket.on('disconnect', function () {
                    $('#messages').append('<li>Disconnected</li>');
                });
            });
        });
    </script>
</head>
<body>
<ul id="messages"></ul>
</body>
</html>

And the server.js

var fs = require('fs'),
    http = require('http'),
    redis = require("redis"),
    sio = require('socket.io');

var server = http.createServer(function (req, res) {
    res.writeHead(200, { 'Content-type': 'text/html'});
    res.end(fs.readFileSync('./index.html'));
});
server.listen(8000, function () {
    console.log('Server listening at http://localhost:8000/');
});

// Attach the socket.io server
io = sio.listen(server);

var chanelId = null
io.set('authorization', function (data, accept) {
    if (!data.query.token) {
        return accept('No token transmitted.', false);
    }
    if (!data.query.chanelId) {
        return accept('No chanelId transmitted.', false);
    }
    var token = data.query.token;
    chanelId = data.query.chanelId;
    // @todo authorize via token
    // to be continued ))
    accept(null, true);
});

var client = redis.createClient();

// Define a message handler
io.sockets.on('connection', function (socket) {

    client.subscribe("channel." + chanelId);
    client.on("message", function (channel, message) {
        //message = JSON.parse(message)

        // just catch and emit to the client
        console.log(channel + ": " + message);
        socket.broadcast.emit('message', message);
    });

});

For publishing events http://redis.io/commands/publish
For checking the queue redis-cli > monitor
Run the our server node server.js
Here’s what I eventually got

sockets