Socket io in node app on google app engine - node.js

I'd like to run a p2p chat written in node js with socket io on GAE.
My app works locally fine but I get error messages when I run it on the GAE servers related to the socket io I think.
Here are the two relevant script tags of my local client.html when running locally:
<script src="/socket.io/socket.io.js"></script>
<!-- <script src="https://cdn.socket.io/socket.io-1.2.0.js"></script> -->
<script type="text/javascript">
// our socket.io code goes here
var socketio = io.connect("127.0.0.1:1337");
socketio.on("message_to_client", function (data) {
to_history(data['message']);
});
function send_message() {
var msg = [document.getElementById("text1").value, user1, uuid];
socketio.emit("message_to_server", {
message: msg
});
}
</script>
I've seen blogs/posts saying that for deployment I need to allow a firewall rule here on SO (which is in place now). I also tried pointing my deployed app to a static external IP like (after making it static in my google cloud console):
var socketio = io.connect('https://104.197.51.XXX')
or to point it to the port 65080 specified in my firewall rule (see documentation by google here:
var socketio = io.connect('https://104.197.51.XXX:65080')
None of this works.
I have the html loaded fine and the jQuery part I have and css is also loading just fine. It's just the socket stuff that I seem to be getting wrong. What do I have to change?
If this is of use, here the app.yaml:
runtime: nodejs
vm: true
Any help is greatly appreciated. Thanks.

Sadly, App Engine just doesn't support websockets (yet). The hack-around you're using is really unreliable for a few reasons:
it makes a direct connection to the instance, which can go down or be recycled at any time
Short of magic hackery, there's really no way to get https going down this route.
In short - this is not production ready. That having been said....
https://github.com/GoogleCloudPlatform/nodejs-docs-samples/tree/master/appengine/websockets
That link will show you a working example and instructions of how to set it up.
Instead of that - I'd suggest using pubnub:
https://www.pubnub.com/docs/nodejs-javascript/pubnub-javascript-sdk
It has a really nice API, and is going to be way more reliable than anything you can hack together with App Engine (you know, until we fix this). You can see a few examples that I've done here:
https://github.com/JustinBeckwith/cloudcats/blob/master/web/public/script.js
https://github.com/JustinBeckwith/hatspin/blob/master/public/script.js
I hope this helps!

I also made the similar chat webapp recently and deployed it on heroku (https://chatterboxxx.herokuapp.com). I also used socket.io for this. I am not sure of GAE, but I don't think you need to specify any IP address in your socket.io js code.
I think you should use
var socketio = io();
instead of
var socketio = io.connect("127.0.0.1:1337");
This works well for me.

Related

How to separate express server code from Express business logic code?

All the Node.js tutorials that I have followed have put everything in one file. It includes importing of libraries, routing, database connecting and starting of the server, by say, express.js:
var app = require('express');
app.get('/somePath', blah blah);
app.listen(...);
Now, I have 4 node servers behind an Nginx load balancer. It then becomes very difficult to have the source code updated on all the four servers.
Is there a way to keep the source code out of the server creation code in such a way that I can deploy the source code on the servers as one package? The server creation code should not know anything about routing or database connections. It should only be listening to changes in a folder and the moment a new module meta file appears, it starts hosting that web application.
Much like how we deploy a Java code packaged as war by Maven and deployed to the webapp of Tomcat, because Tomcat instantiation is not part of the source code. In node.js it seems server is also part of the source code.
For now, the packaging is not my concern. My concern is how to separate the logic and how do I point all my servers to one source code base?
Node.js or JavaScript for that matter doesn't have a concept like WAR. But what it does have is something similar. To achieve something WAR like, you would essentially bundle the code into one source file using something like webpack. However, this will probably not work with Node.js modules like http (Express uses `http since it likely calls or relies on native V8/C++ functions/libraries.
You could also use Docker and think of the Docker containers as WARs.
Here is what I figured out as a work around:
Keep the servers under a folder say, "server_clusters" and put different node servers there, namely: node1.js, node2.js, node3.js, node4.js, etc (I know, in the real world, the clusters would be different VMs or CPUs altogether but for now, I simply want to separate server creation logic from source code). These files would have this code snippet:
var constants = require('./prop');
var appBasePath = constants.APP_BASE_DIR;
var appFilePath = appBasePath + "/main";
var app = require(appFilePath);
//each server would have just different port number while everything else would remain constant
app.listen(8080, function (req, res) {
console.log("server started up");
});
Create a properties file that would have the path to the source code and export the object. That simple. This is what is used on line#1 in the above code
Create the source directory project wherever you want on the machine and just update its home directory in the constant file above. The source code directory can export one landing file that will provide the express app to the servers to start:
var express = require('express');
var app = express();
module.exports = app;
With this, there are multiple servers that are pointing to the same source code.
Hope this helps to those who are facing the same problem.
Other approaches are welcome.

socket.volatile.emit from client side

I am developing a simple application, with a node.js server, and an HTML5 client in browser. At the moment, I am using socket.io for the communication, because it seems to me that it should work in most cases: proxies, firewalls, etc. On the other hand, I find hard to now precisely what is going on, as a lot of things are automated, and as I did not find a comprehensive documentation. One other important point is that I am new to the Javascript/Node.js world.
In this particular question, I am trying to achieve a tight synchronisation between clients and a server, following an SNTP-like scheme. Therefore, I would like to drop any delayed packet. The volatile flag should allow me to do this, and I use it on to emit messages from the server, but it does not seem valid from the client side. Is it by design? Because I am using the stand-alone version on the client (no require or browserify here)?
index.html
<html>
<body onload="init()">
<script src="/socket.io/socket.io.js"></script>
<script src="calibration.js"></script>
</body>
</html>
calibration.js
var socket = io.connect();
function init() {
socket.emit('test', 'ok');
socket.volatile.emit('test-volatile', 'bad');
}
console log on page load
socket.volatile is undefined
Is volatile pointless from the client side anyway? If not, is there a way to use it? Any pointer to documentation would be appreciated. At the moment, I am considering engine.io or ws node.js packages...
I think sending volatile messages from the client to the server is not supported yet.
https://github.com/socketio/socket.io-client/issues/283
https://github.com/socketio/socket.io-client/pull/821
I am using socket.io-client to send a volatile emit from client to server. But, as I am sending the message right after the connection I had to use a setTimeout()
const socket = io( { autoConnect: false });
function init(){
socket.open();
setTimeout(() => {
socket.volatile.emit('hello', 'world');
}, 1000);
}

I am getting "io is not defined" error

I am using this on the client
<script type="text/javascript" src="http://domain.com:8440/socket.io/socket.io.js"></script>
When the server is too busy, sometimes it gives an "io not defined" error on the client. How can I resolve this ?
Here is my server code
var db_helper = require("./db.js");
var io=require('socket.io').listen(8440);
var check = require('validator').check,
sanitize = require('validator').sanitize;
var roomid=0;
var anonid;
var ilet;
var userip;
var blck_id;
io.set('transports', [
, 'xhr-polling'
, 'websocket'
, 'jsonp-polling'
]);
The server has 16 GB RAM and 13.6 GHz CPU.
Keep in mind node.js apps run in a single thread unless you're using something like Cluster to run more. This means that if you're doing something that blocks, it's possible for the requests to http://domain.com:8440/socket.io/socket.io.js to timeout, which would cause your io not defined error. You should see a 404 error in your console logs as well if / when this happens.
Try this out,
get the clientside socketio library and put it in the folder from where the js files are served. Point the script location to this file location.
You will find the client side script here
<server node_moudules>\socket.io\node_modules\socket.io-client\dist\socket.io.js
In the first place, as pointed by #Timothy try to find out why the node is getting busy.
You can try to serve the socket.io.js file from a regular web server, as Chandu pointed out.
This should at least offload the node.js server from that load.
Secondly - and this is more important - look at what is blocking your node.js server. As node.js is single threaded, you should by all means avoid long-running operations.
Can you give an example of the code you are running in node?

Trying deploy nodejs

I'm noob on nodejs and i'm trying some tutorials of nodejs. I'm trying this tutorial: http://cestfait.ch/content/chat-webapp-nodejs it works wonderful on my localhost but not when I upload to appfog like you can see here: http://nodebruno.hp.af.cm/
For example, the prompt don't show up. I changed the code to avoid the prompt and insert the nickname on a input text and this work on localhost but doesn't work on appfog too.
I already tried on nodejitsu servers and I have the same problem
Can you help me ?
Your app has an error, it's trying to connect to a localhost socket.io server.
You need to change this line:
var socket = io.connect('http://localhost:8000');
to
var socket = io.connect();
And it would work preferably on Nodejitsu

Differences between socket.io and websockets

What are the differences between socket.io and websockets in
node.js?
Are they both server push technologies?
The only differences I felt was,
socket.io allowed me to send/emit messages by specifying an event name.
In the case of socket.io a message from server will reach on all clients, but for the same in websockets I was forced to keep an array of all connections and loop through it to send messages to all clients.
Also,
I wonder why web inspectors (like Chrome/firebug/fiddler) are unable to catch these messages (from socket.io/websocket) from server?
Please clarify this.
Misconceptions
There are few common misconceptions regarding WebSocket and Socket.IO:
The first misconception is that using Socket.IO is significantly easier than using WebSocket which doesn't seem to be the case. See examples below.
The second misconception is that WebSocket is not widely supported in the browsers. See below for more info.
The third misconception is that Socket.IO downgrades the connection as a fallback on older browsers. It actually assumes that the browser is old and starts an AJAX connection to the server, that gets later upgraded on browsers supporting WebSocket, after some traffic is exchanged. See below for details.
My experiment
I wrote an npm module to demonstrate the difference between WebSocket and Socket.IO:
https://www.npmjs.com/package/websocket-vs-socket.io
https://github.com/rsp/node-websocket-vs-socket.io
It is a simple example of server-side and client-side code - the client connects to the server using either WebSocket or Socket.IO and the server sends three messages in 1s intervals, which are added to the DOM by the client.
Server-side
Compare the server-side example of using WebSocket and Socket.IO to do the same in an Express.js app:
WebSocket Server
WebSocket server example using Express.js:
var path = require('path');
var app = require('express')();
var ws = require('express-ws')(app);
app.get('/', (req, res) => {
console.error('express connection');
res.sendFile(path.join(__dirname, 'ws.html'));
});
app.ws('/', (s, req) => {
console.error('websocket connection');
for (var t = 0; t < 3; t++)
setTimeout(() => s.send('message from server', ()=>{}), 1000*t);
});
app.listen(3001, () => console.error('listening on http://localhost:3001/'));
console.error('websocket example');
Source: https://github.com/rsp/node-websocket-vs-socket.io/blob/master/ws.js
Socket.IO Server
Socket.IO server example using Express.js:
var path = require('path');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
console.error('express connection');
res.sendFile(path.join(__dirname, 'si.html'));
});
io.on('connection', s => {
console.error('socket.io connection');
for (var t = 0; t < 3; t++)
setTimeout(() => s.emit('message', 'message from server'), 1000*t);
});
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
console.error('socket.io example');
Source: https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.js
Client-side
Compare the client-side example of using WebSocket and Socket.IO to do the same in the browser:
WebSocket Client
WebSocket client example using vanilla JavaScript:
var l = document.getElementById('l');
var log = function (m) {
var i = document.createElement('li');
i.innerText = new Date().toISOString()+' '+m;
l.appendChild(i);
}
log('opening websocket connection');
var s = new WebSocket('ws://'+window.location.host+'/');
s.addEventListener('error', function (m) { log("error"); });
s.addEventListener('open', function (m) { log("websocket connection open"); });
s.addEventListener('message', function (m) { log(m.data); });
Source: https://github.com/rsp/node-websocket-vs-socket.io/blob/master/ws.html
Socket.IO Client
Socket.IO client example using vanilla JavaScript:
var l = document.getElementById('l');
var log = function (m) {
var i = document.createElement('li');
i.innerText = new Date().toISOString()+' '+m;
l.appendChild(i);
}
log('opening socket.io connection');
var s = io();
s.on('connect_error', function (m) { log("error"); });
s.on('connect', function (m) { log("socket.io connection open"); });
s.on('message', function (m) { log(m); });
Source: https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.html
Network traffic
To see the difference in network traffic you can run my test. Here are the results that I got:
WebSocket Results
2 requests, 1.50 KB, 0.05 s
From those 2 requests:
HTML page itself
connection upgrade to WebSocket
(The connection upgrade request is visible on the developer tools with a 101 Switching Protocols response.)
Socket.IO Results
6 requests, 181.56 KB, 0.25 s
From those 6 requests:
the HTML page itself
Socket.IO's JavaScript (180 kilobytes)
first long polling AJAX request
second long polling AJAX request
third long polling AJAX request
connection upgrade to WebSocket
Screenshots
WebSocket results that I got on localhost:
Socket.IO results that I got on localhost:
Test yourself
Quick start:
# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io
Open http://localhost:3001/ in your browser, open developer tools with Shift+Ctrl+I, open the Network tab and reload the page with Ctrl+R to see the network traffic for the WebSocket version.
Open http://localhost:3002/ in your browser, open developer tools with Shift+Ctrl+I, open the Network tab and reload the page with Ctrl+R to see the network traffic for the Socket.IO version.
To uninstall:
# Uninstall:
npm rm -g websocket-vs-socket.io
Browser compatibility
As of June 2016 WebSocket works on everything except Opera Mini, including IE higher than 9.
This is the browser compatibility of WebSocket on Can I Use as of June 2016:
See http://caniuse.com/websockets for up-to-date info.
Its advantages are that it simplifies the usage of WebSockets as you described in #2, and probably more importantly it provides fail-overs to other protocols in the event that WebSockets are not supported on the browser or server. I would avoid using WebSockets directly unless you are very familiar with what environments they don't work and you are capable of working around those limitations.
This is a good read on both WebSockets and Socket.IO.
http://davidwalsh.name/websocket
tl;dr;
Comparing them is like comparing Restaurant food (maybe expensive sometimes, and maybe not 100% you want it) with homemade food, where you have to gather and grow each one of the ingredients on your own.
Maybe if you just want to eat an apple, the latter is better. But if you want something complicated and you're alone, it's really not worth cooking and making all the ingredients by yourself.
I've worked with both of these. Here is my experience.
SocketIO
Has autoconnect
Has namespaces
Has rooms
Has subscriptions service
Has a pre-designed protocol of communication
(talking about the protocol to subscribe, unsubscribe or send a message to a specific room, you must all design them yourself in websockets)
Has good logging support
Has integration with services such as redis
Has fallback in case WS is not supported (well, it's more and more rare circumstance though)
It's a library. Which means, it's actually helping your cause in every way. Websockets is a protocol, not a library, which SocketIO uses anyway.
The whole architecture is supported and designed by someone who is not you, thus you dont have to spend time designing and implementing anything from the above, but you can go straight to coding business rules.
Has a community because it's a library (you can't have a community for HTTP or Websockets :P They're just standards/protocols)
Websockets
You have the absolute control, depending on who you are, this can be very good or very bad
It's as light as it gets (remember, its a protocol, not a library)
You design your own architecture & protocol
Has no autoconnect, you implement it yourself if yo want it
Has no subscription service, you design it
Has no logging, you implement it
Has no fallback support
Has no rooms, or namespaces. If you want such concepts, you implement them yourself
Has no support for anything, you will be the one who implements everything
You first have to focus on the technical parts and designing everything that comes and goes from and to your Websockets
You have to debug your designs first, and this is going to take you a long time
Obviously, you can see I'm biased to SocketIO. I would love to say so, but I'm really really not.
I'm really battling not to use SocketIO. I dont wanna use it. I like designing my own stuff and solving my own problems myself.
But if you want to have a business and not just a 1000 lines project, and you're going to choose Websockets, you're going to have to implement every single thing yourself. You have to debug everything. You have to make your own subscription service. Your own protocol. Your own everything. And you have to make sure everything is quite sophisticated. And you'll make A LOT of mistakes along the way. You'll spend tons of time designing and debugging everything. I did and still do. I'm using websockets and the reason I'm here is because they're unbearable for a one guy trying to deal with solving business rules for his startup and instead dealing with Websocket designing jargon.
Choosing Websockets for a big application ain't an easy option if you're a one guy army or a small team trying to implement complex features. I've wrote more code in Websockets than I ever wrote with SocketIO in the past, for ten times simpler things than I did with SocketIO.
All I have to say is ... Choose SocketIO if you want a finished product and design. (unless you want something very simple in functionality)
Im going to provide an argument against using socket.io.
I think using socket.io solely because it has fallbacks isnt a good idea. Let IE8 RIP.
In the past there have been many cases where new versions of NodeJS has broken socket.io. You can check these lists for examples... https://github.com/socketio/socket.io/issues?q=install+error
If you go to develop an Android app or something that needs to work with your existing app, you would probably be okay working with WS right away, socket.io might give you some trouble there...
Plus the WS module for Node.JS is amazingly simple to use.
Using Socket.IO is basically like using jQuery - you want to support older browsers, you need to write less code and the library will provide with fallbacks. Socket.io uses the websockets technology if available, and if not, checks the best communication type available and uses it.
https://socket.io/docs/#What-Socket-IO-is-not (with my emphasis)
What Socket.IO is not
Socket.IO is NOT a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the packet id when a message acknowledgement is needed. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a WebSocket server either. Please see the protocol specification here.
// WARNING: the client will NOT be able to connect!
const client = io('ws://echo.websocket.org');
I would like provide one more answer in 2021. socket.io has become actively maintained again since 2020 Sept. During 2019 to 2020 Aug(almost 2 years) there was basically no activity at all and I had thought the project may be dead.
Socket.io also published an article called Why Socket.IO in 2020?, except for a fallback to HTTP long-polling, I think these 2 features are what socket.io provides and websocket lacks of
auto-reconnection
a way to broadcast data to a given set of clients (rooms/namespace)
One more feature I find socket.io convenient is for ws server development, especially I use docker for my server deployment. Because I always start more than 1 server instances, cross ws server communication is a must and socket.io provide https://socket.io/docs/v4/redis-adapter/ for it.
With redis-adapter, scaling server process to multiple nodes is easy while load balance for ws server is hard. Check here https://socket.io/docs/v4/using-multiple-nodes/ for further information.
Even if modern browsers support WebSockets now, I think there is no need to throw SocketIO away and it still has its place in any nowadays project. It's easy to understand, and personally, I learned how WebSockets work thanks to SocketIO.
As said in this topic, there's a plenty of integration libraries for Angular, React, etc. and definition types for TypeScript and other programming languages.
The other point I would add to the differences between Socket.io and WebSockets is that clustering with Socket.io is not a big deal. Socket.io offers Adapters that can be used to link it with Redis to enhance scalability. You have ioredis and socket.io-redis for example.
Yes I know, SocketCluster exists, but that's off-topic.
Socket.IO uses WebSocket and when WebSocket is not available uses fallback algo to make real time connections.
TLDR:
'Socket.io' is an application layer specification that can be implemented on top of/using the application layer specification 'websockets'.
websocket spec
socket.io spec
I think the simple answer here is in basic web technology definitions:
Specification: A documented standard detailing the requirements for a program to achieve in order to be labeled as "an implimentation of some sepc." It is important to achieve this rubber stamp when building programs, because any program is only as good at the machine executing the code. Programming is fundamentally built upon specifications, and if, they are not followed code will not execute correctly. However, a specification does nothing. It is just a text document.
Implementation: This is actual, executable code that accomplishes what the specification says to do.
Application Layer - System that defines messages and handshakes sent over transport. This is the stuff you have to know when working with HTTP/Websockets/Socketio. It defines how the connections will be made, authenticated, data will be sent, and how it will arrive.

Resources