简体   繁体   中英

How to set RedisStore — Node, Express, Socket.io, Heroku

I'm using Node & Express 4.0 deployed on Heroku, and I'm trying to implement Socket.io with Redis as aa session store. So I have this as my current code:

 var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var RedisStore = io.RedisStore;

if (process.env.REDISTOGO_URL) {
    // inside if statement
    var rtg   = require("url").parse(process.env.REDISTOGO_URL);
    var redis = require("redis").createClient(rtg.port, rtg.hostname);

    redis.auth(rtg.auth.split(":")[1]);
} else {
    var redis = require("redis").createClient();
}

/** Initialize RedisStore for socket.io **/
io.set('store', new RedisStore({
  redis    : redis
}));

But I get the following error:

14:25:03 web.1  | io.set('store', new RedisStore({
14:25:03 web.1  |                 ^
14:25:03 web.1  | TypeError: undefined is not a function

I've also seen this way of defining a RedisStore:

var redis = require('socket.io/node_modules/redis');
var RedisStore = require('socket.io/lib/stores/redis');

However, my installed version of socket.io, installed using npm install --save socket.io , doesn't include stores in the lib directory:

在此输入图像描述


EDIT

I saw this on the socket.io page in regards to their 1.0 release:

// 2. Implement the socket.io-redis adapter

var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));

But there's no other documentation I could find regarding this new module, and since I'm new to this whole stack, I don't think I could figure it out on my own.

The trend among node.js modules is to remove functionality that isn't truly core to the module.

Which is why socket.io 1.0 no longer supports redis out of the box.

So step one is to track down the functionality you need.

  1. http://socket.io/docs/server-api/
  2. https://github.com/Automattic/socket.io-adapter
  3. https://github.com/Automattic/socket.io-redis

Then you need to install the other module npm install socket.io-redis --save

And finally configure your app.

var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var redis = require('socket.io-redis');

io.adapter(redis(process.env.REDISTOGO_URL));

The nice part is the socket.io-redis adapter accepts redis urls and defaults to localhost:6379 so you (should) be able to simple pass in the REDISTOGO_URL

I had to parse libraries above to get this example, so I figured I would post a full blown example, but I must admit there are a couple of things off, this uses REDISCLOUD, it is on Heroku, it does work. I'll post this elsewhere and maybe put it in a doc too.

var redis = require('redis');
var ioredis = require('socket.io-redis'); //Adapter
var url = require('url'); 
var redisURL = url.parse(process.env.REDISCLOUD_URL );

var pub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true});
var sub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true});
pub.auth(redisURL.auth.split(":")[1]);
sub.auth(redisURL.auth.split(":")[1]);

var redisOptions = {
  pubClient: pub,
  subClient: sub,
  host: redisURL.hostname,
  port: redisURL.port
};

io.adapter(ioredis(redisOptions));

Following code works for me with Heroku Redis, hope this helps.

var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);

var redis = require('redis');
var redisAdapter = require('socket.io-redis');

io.adapter(redisAdapter({
    pubClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true}),
    subClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true})
}));

For the ones interested, this is my prototype chat server running on newest socket.io with express, multiple cores and redis as an intermediate. Broadcasted messages are send to all room users no matter if they are connected to a different node and port instance. Just run

  • node server.js

and on other machines

  • node client.js
  • or for testing node client.js 7001, 7002, 7003 ......

server.js

  var options = {
    //workers: 2, // total workers (default: cpu cores count).
    first_port: 7000, // 8000, 8001 are worker's ports (default: 8000).
    proxy_port: 5000, // default (5000).
    session_hash: function (req, res) { return req.connection.remoteAddress; },
    no_sockets: false // allow socket.io proxy (default: false).
    };

require('sticky-socket-cluster')(options, start);

function start(port) {
    // requirements
    var express = require('express');
    var http = require('http');
    var socketio = require('socket.io');
    var path = require('path');
    var sticky = require('sticky-session');

    var app = express();

    var server = http.createServer(app);
    var io = socketio.listen(server);

    var redis = require('socket.io-redis');
    io.adapter(redis({ host: 'localhost', port: 6379 }));

    server.listen(port, function() {
      console.log(' - listening on ' + port+ ' ' + __dirname);
    });

    // require our chatserver
    var ChatServer = require('./chatserver');

    // initialize a new chat server.
    new ChatServer({io: io, port: port}).init();
}

chatserver.js

RoomUtil = (function(){

    roomMessages = {};

    return {

        getMessages : function(room_id,limit,cb){
            //TODO
            cb(roomMessages[room_id] || []);
        },

        postMessage : function(message,room_id,cb){

            if (!roomMessages[room_id]) roomMessages[room_id] = [];
            roomMessages[room_id].push(message);
            cb();
        }
    }   
})();

var Server = function(options) {
  var self = this;

  self.io = options.io;

  // users array
  self.users = [];

  // initialize function
  self.init = function() {
      console.log("init");
    // Fired upon a connection
    self.io.on('connection', function(socket) {
      console.log("incoming connection");
     // var ru = new RoomUser();
      self.handleConnection(socket,options.port);
    });
  }

  // socket handler for an incoming socket
  self.handleConnection = function(socket,port) {
    // wait for a login message

    socket.emit("incoming connection",{}); 

    socket.on("joinroom",function(data,joinroom_callback){

        console.log("attempt to join room ",data.room_id," on port ",port);
        if (!data.room_id){
            console.log("cannon join room -> no room id given");
            return socket.disconnect();
        }
        else{

            var room_id = data.room_id;

            socket.join(room_id,function(){

                console.log(socket.rooms);

                RoomUtil.getMessages(data.room_id,50,function(messages){
                    console.log("client succesfully joined room ",data.room_id);
                    joinroom_callback(null,{'messages':messages});
                });

                socket.on("login",function(data,login_callback){

                    if (!data.username){
                        login_callback("invalid userdata",null);        
                    }
                    else{

                        login_callback(null,1);

                        socket.on("post_message",function(data,message_callback){

                            if (!data.message || data.message == ""){
                                console.log("empty message posted. ignore");
                                message_callback("invalid_message",null);
                            }
                            else{
                                console.log("received message on port ",port,data.message);
                                message_callback(null,1);
                                RoomUtil.postMessage(data.message,room_id,function(){
                                    RoomUtil.getMessages(room_id,50,function(messages){
                                        console.log("emit messages to room id ",room_id);
                                        //socket.to(room_id).emit('update_messages', messages);
                                        //socket.broadcast.to(room_id).emit('update_messages', messages);
                                        //socket.broadcast.to(room_id).emit('update_messages', messages);
                                        //self.io.to(room_id).emit('update_messages', messages);
                                        self.io.in(room_id).emit('update_messages', messages);
                                    });
                                })
                            }
                        });
                    }       
                });
            });
        }
    });
  }
}

module.exports = Server;

client.js

var servercon = 'http://localhost:'+(process.argv[2] || 5000);

console.log("going to connect to "+servercon)
var socket = require('socket.io-client')(servercon); 

var readline = require('readline');

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

socket.on('connect', function(){
    console.log("connected, going to login");

    socket.emit("joinroom",{"room_id":123123}, function(error,data){

        if (error){
            console.log("cannot join room ",error);
        }
        else{
            console.log("succesfully joined room -> going to login now");

            console.log("received messages count",data.messages.length);

            socket.emit("login",{username:"John Mckain"}, function(error, message){

                if (error){
                    console.log("error logging in ",error);
                }
                else{
                    console.log("logged in succesfully -> post message now");

                    var readline = function(){
                        rl.question("type in a message -> ", function(message) {

                            socket.emit("post_message",{'message':message}, function(error, message){

                                if (error){
                                    console.log("error posting message");
                                    readline();
                                }
                                else{
                                    console.log("succesfully posted message");
                                    readline();
                                }

                            });
                        });
                    }
                    readline();
                }

            });

            socket.on("update_messages",function(data){
                console.log("received new messages count ",data.length,data);
            });
        }
    });
});
socket.on('event', function(data){
    console.log("event send",data);
});
socket.on('disconnect', function(e){
    console.log("disconnected",e);
});

socket.on("welcome",function(data){
    console.log("on welcome ",data)
})

socket.on("pong",function(e){
    console.log("pong")
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM