I want to create a websocket server with NodeJS and Socket.IO but it wont work.
I tried several scripts which people used in their tutorials but always when i connect i get error: undefined.
~MrJoki007
var server = require( 'http' ).createServer( app );
server.listen( 3009 ); //port for your socket...
var socket = require( 'socket.io' );
var io = socket.listen( server );
make sure you install socket.io
Related
Briefly: I created a service on an internet server using Cro and websocket. Very simple using Cro examples. No problem when sending and receiving data from an HTML page when the page is served as localhost. When the page is served using https, the websocket cannot be established.
How is the wss protocol be used with Cro?
Update: After installing cro and running cro stub :secure, the service.p6 has some more code not explicit in the documentation.
More detail:
I have a docker file running on the internet server, Cro is set to listen on 35145, so the docker command is docker --rm -t myApp -p 35145:35145
The service file contains
use Cro::HTTP::Log::File;
use Cro::HTTP::Server;
use Cro::HTTP::Router;
use Cro::HTTP::Router::WebSocket;
my $host = %*ENV<RAKU_WEB_REPL_HOST> // '0.0.0.0';
my $port = %*ENV<RAKU_WEB_REPL_PORT> // 35145;
my Cro::Service $http = Cro::HTTP::Server.new(
http => <1.1>,
:$host,
:$port,
application => routes(),
after => [
Cro::HTTP::Log::File.new(logs => $*OUT, errors => $*ERR)
]
);
$http.start;
react {
whenever signal(SIGINT) {
say "Shutting down...";
$http.stop;
done;
}
}
sub routes() {
route {
get -> 'raku' {
web-socket :json, -> $incoming {
supply whenever $incoming -> $message {
my $json = await $message.body;
if $json<code> {
my $stdout, $stderr;
# process code
emit({ :$stdout, :$stderr })
}
}
}
}
}
}
In the HTML I have a textarea container with an id raku-code. The js script has the following (I set websocketHost and websocketPort elsewhere in the script) in a handler that fires after the DOM is ready:
const connect = function() {
// Return a promise, which will wait for the socket to open
return new Promise((resolve, reject) => {
// This calculates the link to the websocket.
const socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:');
const socketUrl = `${socketProtocol}//${websocketHost}:${websocketPort}/raku`;
socket = new WebSocket(socketUrl);
// This will fire once the socket opens
socket.onopen = (e) => {
// Send a little test data, which we can use on the server if we want
socket.send(JSON.stringify({ "loaded" : true }));
// Resolve the promise - we are connected
resolve();
}
// This will fire when the server sends the user a message
socket.onmessage = (data) => {
let parsedData = JSON.parse(data.data);
const resOut = document.getElementById('raku-ws-stdout');
const resErr = document.getElementById('raku-ws-stderr');
resOut.textContent = parsedData.stdout;
resErr.textContent = parsedData.stderr;
}
When an HTML file with this JS script is set up, and served locally I can send data to the Cro app running on an internet server, and the Cro App (running in a docker image) processes and returns data which is placed in the right HTML container. Using Firefox and the developer tools, I can see that the ws connection is created.
But when I serve the same file via Apache which forces access via https, Firefox issues an error that the 'wss' connection cannot be created. In addition, if I force a 'ws' connection in the JS script, Firefox prevents the creation of a non-secure connection.
a) How do I change the Cro coding to allow for wss? From the Cro documentation it seems I need to add a Cro::TLS listener, but it isn't clear where to instantiate the listener.
b) If this is to be in a docker file, would I need to include the secret encryption keys in the image, which is not something I would like to do?
c) Is there a way to put the Cro app behind the Apache server so that the websocket is decrypted/encrypted by Apache?
How do I change the Cro coding to allow for wss? From the Cro documentation it seems I need to add a Cro::TLS listener, but it isn't clear where to instantiate the listener.
Just pass the needed arguments to Cro::HTTP::Server, it will set up the listener for you.
If this is to be in a docker file, would I need to include the secret encryption keys in the image, which is not something I would like to do?
No. You can keep them in a volume, or bind-mount them from the host machine.
Is there a way to put the Cro app behind the Apache server so that the websocket is decrypted/encrypted by Apache?
Yes, same as with any other app. Use mod_proxy, mod_proxy_wstunnel and a ProxyPass command. Other frontends such as nginx, haproxy, or envoy will also do the job.
Though is not a pure cro solution, but you can
run your cro app on (none ssl/https) http/web socket port - localhost
and then have an Nginx server (configured to serve https/ssl trafic) to handle incoming public https/ssl requests and bypass them
as a plain http traffic to your app using
nginx reverse proxy mechanism (this is also often referred as an ssl termination), that way you
remove a necessity to handle https/ssl on cro side.
The only hurdle here might be if a web sockets
protocol is handled well by Nginx proxy. I’ve never tried that but probably you should be fine according to the Nginx docs - https://www.nginx.com/blog/websocket-nginx/
I am building a Titanium based mobile application (iOS) in Appcelerator and want to connect it to Node.js(Socket.io) based server. For that I need a client side socket.io file which.
I tried to import the client side JS using 'require',
var io = require('socket.io'); //JavaScript Downloaded from here: https://github.com/socketio/socket.io-client/blob/master/socket.io.js
var socket = io.connect('http://localhost:3000');
I am getting the following error:
Script Error: Module "socket.io" failed to leave a valid exports object
Please let me know where I am going wrong or what is the way to use socket.io in Appcelerator.
Thanks In Advance.
I wanted to use socket.io in my RN project. Everything was ok, until I disabled chrome debugger. Now socket.io just doesn't work, nothing happens.
This is not the same problem: Is it possible to combine React Native with socket.io
What's your React Native version?
In your url add ws:// like :
var soc = socket('ws://192.168.1.101',{
jsonp: false
})
It works fine on device with RN v0.21.0.
After I upgrade RN to 0.24.0, it doesn't work again.
I have also got this problem. I fixed this from this link
You have to initialize socket like this
this.socket = io('http://192.168.0.101', {jsonp: false, transports: ['websocket']});
I'm trying to use the express middleware for sessions (I'm not understanding but I feel that I am very close).
the reason I have ended up asking is that the express docs (http://expressjs.com/api.html#middleware) are calling it express.cookieSession where as everyone else (mostly on here) Ive seen discussing it have been calling it express.session. I'm really not sure now, I just have a big lump of possibly useful code ??? but every example I see is different ... how does it work?
var express = require('express')
, http = require('http');
, app = express();
store = new express.session.MemoryStore;
app.use(express.cookieParser());
//app.use(express.cookieSession());
app.use(express.session({secret:'whateverman',key:'express.sid',store:store}));
app.use(app.router);
app.all('/*',function(req,res,next){res.header("Access-Control-Allow-Origin","*");res.header("Access-Control-Allow-Headers","X-Requested-With");next();});
var server = http.createServer(app);
server.listen(8000);
var io = require('socket.io').listen(server);
io.sockets.on('connection',function(socket){
socket.on('reglogin',function(_){_.session.e='some#email.com';});
});
socket.on('reglogin' produces:
TypeError: Cannot set property 'e' of undefined
//-------------------------------update on question
if express is dependant on connect but express can access connects middleware as if it were its own, eg:
app.use(express.cookieSession()); //app is express
app.use(connect.cookieSession()); //does exactly the same
then surely the same logic would apply to socket.io which is dependant on express:
io.use(connect.CookieSession()); //io is socket.io
Am I wrong here? does Socket.io have the same .use method? update:(answer is no to io.use)
io.interoperate(app.use(express.cookieSession())); LOL
----------------------------UPDATE---------------------------------
I've followed the following npm modules guide lines in a despirate attemp to get sessions working and filed each and every time on handshake with no cookie:
express.io
session.socket.io
session.io + sessionstore
currently using the latter with console log:
warn - handshake error Could not find cookie with key: connect.sid
I'm having fully functional user signup/authentication system using express and connect middleware.
app.use(express.session({store: require('connect').session.MemoryStore( {reapInterval: 60000 * 10} ) }))
The only problem is that sessions drop every time you perform server restart.
https://github.com/remy/nodemon - and nodemon restarts node.js every time it detects a file change.
How can I have persistent sessions ?
Like your code is telling you are using MemoryStore. This is volatile and gets cleared on restart. I would advise you to use connect_redis to persist your session. Redis is an extremely fast store.
Download redis
compile redis: make
Start server: ./redis-server
npm install connect-redis
var connect = require('connect') , RedisStore = require('connect-redis');
connect.createServer(
connect.cookieParser(),
// 5 minutes
connect.session({ store: new RedisStore })
);
This is just to get you started quickly. You should read the documentation and configure redis if you want to get most out of redis.
I was trying to get Redis on track using express.js, Google sent me here. The express implementation changed:
var express = require('express'),
RedisStore = require('connect-redis')(express);
Another important thing is the order of express configurations.
app.configure(function(){
app.enable('strict routing'); // removes trailing slash
app.set('views', __dirname + '/views');
app.set('view engine', 'jqtpl');
app.register('.html', require('jqtpl').express);
app.use(express.favicon());
app.use(express.methodOverride());
app.use(express.compiler({src: __dirname + '/public', enable: ['sass']}));
app.use(express.static(__dirname + '/public'));
app.use(app.router);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({secret: _.config.secret, store: new RedisStore}));
});
cookieParser & session configurations need to be at the end of the configurations, and cookieParser must be placed right before express.session.
Hope that helps, I ran in both of these problems.
I agree with everybody about Redis, but I think that different technologies are a problem in terms of software maintenance. If you are using MongoDB for example there is connect-mongo (https://npmjs.org/package/connect-mongo), if you are using MySQL there is connect-MySQL (https://npmjs.org/package/connect-mysql), connect-couchdb for CouchDB (https://npmjs.org/package/connect-couchdb) and so on.
also, if you're using express, you need to provide a secret when telling the app to use the redis middleware.
so, follow Alfred's recipe above, but do the following...
var express = require( 'express' );
var RedisStore = require('connect-redis');
app.use( express.cookieParser() );
app.use( express.session( { secret: "keyboard cat", store: new RedisStore }));
When node dies I would imagine the memory store you're using dies.
Persist the sessions to disk?