8

I know this question is kind of awkward, but the problem comes from Samsung TV 2010 / 2011 SmartTV (and blue ray player; of course 2012 emulator working fine). I ported the simple chatting examples come from the source and package to SmartTV app. Both of them fall back to JSONP polling, but from SmartTV app only could emit / push to server once. Receiving the message from server could be multiple times without any problem. After looking for the answer in Samsung D forum (of course nothing there), I think the fastest way to work around this issue is to deploy an Express server, taking the post data and JSON.parse, then emit Socket.io / Sockjs internally inside the server itself.

Could anybody show me an easy sample code so I could start from there? Thanks a lot.

I quickly make code, but seems it doesn't work:

lib/server.js

var express = require('express')
  , app = express.createServer()
  , io = require('socket.io').listen(app);

app.listen(80);

app.use(express.bodyParser());

app.get('/', function (req, res) {
  res.sendfile('/var/www/mpgs_lite_v3/index.html');
});

app.post('/', function(req, res){
  console.log(req.body);
  io.sockets.emit('my other event', req.body);
  res.redirect('back');
});

io.sockets.on('connection', function (socket) {
  //socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

index.html

<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
</head>
<body>
<form method="post" action="/">
     <input type="hidden" name="_method" value="put" />
     <input type="text" name="user[name]" />
     <input type="text" name="user[email]" />
     <input type="submit" value="Submit" />
 </form>
</body>
</html>

'my other event' seems not receive anything.

user1045217
  • 506
  • 1
  • 4
  • 9
  • I found the solution. Just move whatever inside the 'my other event' to another function and let both post and emit call it. Although this issue solve, I need to manage the socket that is connect on other line. – user1045217 Feb 25 '12 at 09:01

4 Answers4

16

UPDATE: I updated the example for you to make it more complete. I didn't have an app.listen before, and here is also a client side script which shows that it, indeed, works fine:

<!doctype html>
<html>
    <head>
        <script src="//www.google.com/jsapi"></script>
        <script src="/socket.io/socket.io.js"></script>
        <script>google.load("jquery", "1.7.1")</script>
        <script>
            var socket = io.connect("localhost", {port: 3000});
            socket.on("foo", function(message) { console.log("foo: ", message) });
            $(function() {
                $("button").click(function() {
                    $.post("/foo", { message: $("input").val() });
                });
            });
        </script>
    </head>
    <body>
        <input type=text>A message</input>
        <button>Click me!</button>
    </body>
</html>

And the server, now with an app.listen directive:

var express = require("express"),
    app = express.createServer(),
    io = require("socket.io").listen(app)
    index = require("fs").readFileSync(__dirname + "/index.html", "utf8");

app.use(express.bodyParser());

app.get("/", function(req, res, next) {
    res.send(index);
});

app.post("/foo", function(req, res, next) {
    io.sockets.emit("foo", req.body);
    res.send({});
});

app.listen(3000);

Usage:

node app.js

Navigate to http://localhost:3000/ and click the button. Check your console for output.

Linus Thiel
  • 38,647
  • 9
  • 109
  • 104
  • Linus, what I tried to do is to emit something written in the server (self-emit, express post to socket.io emit). Server push to client mechanism working pretty fine on Samsung SmartTV (I would say StupidTV personally). If I put io.sockets.on("foo", function(message) { // emit another to client or just log on console } after app.listen(3000); it won't do anything. – user1045217 Feb 23 '12 at 22:20
  • for newer version of express : var express = require('express') , http = require('http'); var bodyParser = require('body-parser'); var app = express(); var server = http.createServer(app); var io = require('socket.io').listen(server); server.listen(my_port); – Ahmad Muzakki Apr 03 '16 at 09:49
2

Based on SockJS express example server.js could look like:

var express = require('express');
var sockjs  = require('sockjs');

// 1. Echo sockjs server
var sockjs_opts = {sockjs_url: "http://cdn.sockjs.org/sockjs-0.2.min.js"};

var sockjs_echo = sockjs.createServer(sockjs_opts);
connections = {};
sockjs_echo.on('connection', function(conn) {
    console.log(conn.id);
    connections[conn.id] = conn
    conn.on('close', function() {
        delete connections[conn.id];
    });

    // Echo.
    conn.on('data', function(message) {
        conn.write(message);
    });
});

// 2. Express server
var app = express.createServer();
sockjs_echo.installHandlers(app, {prefix:'/echo'});

console.log(' [*] Listening on 0.0.0.0:9999' );
app.listen(9999, '0.0.0.0');

app.get('/', function (req, res) {
    res.sendfile(__dirname + '/index.html');
});

app.post("/send", function(req, res, next) {
    for(var id in connections) {
        connections[id].write('received POST');
    }
    res.send({});
});

To test open browser at localhost:9999 and run:

curl localhost:9999/send -X POST
Marek
  • 3,471
  • 1
  • 16
  • 15
  • I appreciate your work. However ur example seems not working on my side. 0. I didn't see 'received POST' appear on console. 1. I made a simple client html (index.html) just do a post request. Originally I thought it would mount on localhost:9999/echo/ but it's on localhost:9999/. 2. Same thing happen on post launched from html. – user1045217 Feb 23 '12 at 22:11
1

just remove this comment //socket.emit('news', { hello: 'world' }); to socket.emit('news', { hello: 'world' });

it will work because its emiting data through news and you are listening using my other event instead of 'news' or you can do just listen using 'my other event'

virk
  • 71
  • 1
  • 1
-1

I don't know if this would help, but you can make an emit abstraction on the client based on your browser and then make a separate get function on the server that will handle the request the same way as the socket.on callback. In order to know where to send the information I suggest you use some key that you can store in a hash table in the server and local storage on the client.

For the client:

var emit = function(event, options) {
    if ("WebSocket" in window) {
        socket.emit(event, options);
        console.log("emited via WebSocket");
    } else {
        $.post("http://localhost/emit/" + event, options);
        console.log("emited via AJAX");
    }
}

emit("echo", {
    key: localStorage.getItem("key"),
    data: {
        hello: "world"
    }
});

socket.on("response", function(data) {
    console.log(data.hello); //will print "world"
});

For the server:

var sockets = {};
var echo_handler = function(a) {
    var socket = sockets[a.key];
    var data = a.data;
    socket.emit("response", data);
}

app.post("/emit/:event", function(req, res) {
    var event = req.params.event;
    switch (event) {
    case "echo":
        var a = {
            key: req.param("key"),
            data: req.param("data")
        }
        echo_handler(a);
        break;
    }
});

io.sockets.on("connection", function(socket) {
    socket.on("connect", function(data) {
        sockets[data.key] = socket;
    });
    socket.on("echo", echo_handler);
});

Another way to do this will be to switch to Sockjs and use their patch.

If someone have better solution for Socket.IO it will be appreciated, because I'm already deep into the project and it's too late to switch Socket.IO for Sockjs, and this solution is not to my liking :( .

DaniOcean
  • 596
  • 1
  • 4
  • 8