I'm working on my first node project, I basically followed the thinkster post to get me started. I've managed to build a simple app and now I'm trying to configure socket.io.
The socket.io initialization code and event handlers are not hard to understand, what is really confusing me is how should I organize that code between the bin/www and the app.js files. Both files were generated automatically by express. bin/www depends on the app.js module, the first initiates the server variable which is needed to start up the socket module, so that means I should put all the 'socket.io' code in the bin/www file?
I don't think I should be touching that file though, I would be more comfortable putting that code into app.js or even inside a dedicated file. I think I need to pass the server object reference between modules, but I'm not sure how to do that.
This is the content of the bin/www file:
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('oculus:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
debug('Listening on ' + bind);
}
And this the content of the app.js file:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
// Mongoose
require('./models/Aplicacoes');
mongoose.connect('mongodb://localhost/oculus');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
/**
* Some business code here
*/
....
module.exports = app;
First, let me tell you, what you're trying to do is kinda right. Not to mess with the bin/www would be fine.
But remember express generator is just that. A generator for you to build upon. You generate, and the apply your own modifications.
My choice would be to:
copy bin/www to a new bin/wwwio,
Update the bin/wwwio script to attach socket.io to the created http server.
Update bin/wwwio to require() a new file ../io.js that handles all my socket.io events.
Modifiy package.json to run node ./bin/wwwio on npm start instead of bin/www
You can also look at the answers on this other question about the some topic:
Using socket.io in Express 4 and express-generator's /bin/www
You'll find several approaches to achieving modularity with little touching on the bin/www script.
Try following these simple steps
Install Socket.io with the following command:
npm install --save socket.io
Add the following to app.js:
var sockIO = require('socket.io')(); app.sockIO = sockIO;
In bin/www,
after var server = http.createServer(app), add the following:
var sockIO = app.sockIO; sockIO.listen(server);
To test functionality, in app.js, you can add the line:
sockIO.on('connection', function(socket){ console.log('A client connection occurred!'); });
Now in layout.hbs add the following snippet before the body closing tag < /body >:
<script src="/socket.io/socket.io.js"></script> <script> var socket = io(); </script>
Further, I have created the GIT REPOSITORY for the complete working project of chat with Sockets express generator.
https://github.com/Mohsin05/Sockets-Express-Generator
I hope it will help everyone. ;)
Related
I am working with Swagger, Express and Node to define and run endpoints. A GET request on the localhost/docs returns all the relevant routes. But when I try a GET request on any of the routes, it returns a "Cannot Get /XXX"
Index.js
'use strict';
var fs = require('fs'),
path = require('path'),
// Basic Setup new express
http = require('http'),
express = require('express'),
mysql = require('mysql'),
parser = require('body-parser');
var swaggerTools = require('swagger-tools');
var jsyaml = require('js-yaml');
// Setup express
var app = express();
app.use(parser.json());
app.use(parser.urlencoded({ extended: true }));
app.set('port', process.env.PORT || 5000);
// Database Connection
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'sample_database'
});
try {
connection.connect();
console.log('Database connected!');
} catch(e) {
console.log('Database Connetion failed:' + e);
}
// swaggerRouter configuration
var options = {
swaggerUi: path.join(__dirname, '/swagger.json'),
controllers: path.join(__dirname, './controllers'),
useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode)
};
// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var spec = fs.readFileSync(path.join(__dirname,'api/swagger.yaml'), 'utf8');
var swaggerDoc = jsyaml.safeLoad(spec);
// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
app.use(middleware.swaggerMetadata());
// Validate Swagger requests
app.use(middleware.swaggerValidator());
// Route validated requests to appropriate controller
app.use(middleware.swaggerRouter(options));
// Serve the Swagger documents and Swagger UI
app.use(middleware.swaggerUi());
// Create server
http.createServer(app).listen(app.get('port'), function(){
console.log('Server listening on port ' + app.get('port'));
});
});
While initialising the middleware, I tried using:
app.use(express.static(__dirname + './controllers'));
But the error is still present. I think this has got something to do with the routing but I am not sure where is the error is.
The directory structure for the code is:
-my_app
|
+--controllers
| |
| +--user.js
| +--userService.js
+--index.js
Try use this construction
require('./controllers/<your_routing_file>')(app);
and type routes not in index.js
I have created a simple SOAP server using node-soap which is currently serving the requests from a SOAP client. Now the requirement is to serve both incoming REST and SOAP requests from different clients in future. My question is can I achieve this by using a single Express app(Using the Express.js framework)? I am new to this, so any help would be appreciated. Thanks in advance!
I think prasun gave good example already, but want to share mine with more detail.
I used express and soap, but use http / https for creating server instead of using express
First, below is project structure and I modularized routes folder for RESTful endpoint routers and services folder for Soap WebService endpoints
/config/index.js
/routes/index.js
/services/wsdl/poservice.wsdl
/services/poservice.js
app.js
server.js
create router by express and build endpoint for GET request for root ('/') context path
[ routers/index.js ]
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({"data": "some data"}));
});
module.exports = router;
Build main routing map on app.js
[ app.js ]
var express = require('express');
var bodyParser = require('body-parser');
var indexRouter = require('./routes/index');
var app = express();
app.use(bodyParser.raw({type: function(){return true;}, limit: '5mb'}));
app.use('/', indexRouter);
module.exports = app;
Set service, port and operation object and also publish wsdl from filepath (./services/wsdl/PurchaseOrderServiceV2.wsdl)
[ services/poservice.js ]
var fs = require('fs');
var path = require('path');
var poServiceXml = fs.readFileSync(path.join(path.join(__dirname, 'wsdl'), 'PurchaseOrderServiceV2.wsdl'), 'utf8');
var poService = {
PurchaseOrderService: {
PurchaseOrderServiceSoapHttpPort: {
getPurchaseOrder: function(args) {
console.log(args);
return {
name: args.name
};
}
}
}
};
module.exports = {
service: poService,
xml: poServiceXml
};
This service, port and operation setup is based on the wsdl. Below is snipped wsdl service, port and operation definition
[ services/wsdl/PurchaseOrderServiceV2.wsdl ]
<wsdl:operation name="getPurchaseOrder">
<wsdl:input message="tns:PurchaseOrderService_getPurchaseOrder"/>
<wsdl:output message="tns:PurchaseOrderService_getPurchaseOrderResponse"/>
<wsdl:fault name="ServiceException" message="errors:ServiceException"/>
</wsdl:operation>
:
<wsdl:service name="PurchaseOrderService">
<wsdl:port name="PurchaseOrderServiceSoapHttpPort" binding="tns:PurchaseOrderServiceSoapHttp">
<soap:address location="https://efqf-test.prc.us6.oraclecloud.com:443/prcPoEditDocumentOrder/PurchaseOrderServiceV2"/>
:
Now create server and run RESTful and Soap endpoints
[ server.js ]
var fs = require('fs');
var config = require('./config');
var app = require('./app');
var debug = require('debug')('po-service:server');
var http = require('http');
var https = require('https');
var soap = require('soap');
const poService = require('./services/poservice');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || config.get('app.port'));
app.set('port', port);
/**
* Create HTTP server or HTTPS server
*/
var server = http.createServer(app);
if(config.get('app.https')) {
server = https.createServer({
key: fs.readFileSync(config.get('app.serverkey')),
cert: fs.readFileSync(config.get('app.servercert'))
}, app);
}
/**
* Listen on provided port, on all network interfaces.
*/
function startServer() {
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
soap.listen(server, '/prcPoEditDocumentOrder/PurchaseOrderServiceV2', poService.service, poService.xml);
}
if(!module.parent) {
// Start server if file is run directly
startServer();
} else {
// Export server, if file is referenced via cluster
module.exports = startServer;
}
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
For configuration, I have config module
[ config/index.js ]
var PropertiesReader = require('properties-reader');
var config = new PropertiesReader('app.properties');
module.exports = config;
and below is configuration file
[ app.properties ]
[app]
hostname = localhost
port = 8080
https = false
serverkey = /path/to/signed.key
servercert = /path/to/signed.crt
Now verify RESTful endpoint
$ curl http://localhost:8080/
{"data":"some data"}
Verify Soap endpoint by Advanced REST client
or by SoapUI
Check posted wsdl can be retrievable by browser
From the pull#872 it supports express server out of the box.
expressServer = express();
server = expressServer.listen(51515, function(){
var soapServer = soap.listen(expressServer, '/SayHello', service, wsdl);
});
where \sayHello is the route on which you want to handle wsdl requests.
Also, note that it will support all the middleware and body parsers as well.
For more details on syntax you can see the tests included in this pull request.
Code your express application as usual
var soap = require('soap');
var express = require('express');
var app = express();
app.use('/', express.static(__dirname + '/public'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
/* other express part */
but don't do app.listen
Build your server like this
var server = require('http').createServer(app);
Code soap part and terminate like this
soap.listen(server, '/wsdl', MyService, xml);
server.listen(8080);
If you want also want websocket use server too
var io = require('socket.io')(server);
/* io part */
I've been bouncing back and forth between socket.io and express.io - but settled for socket.io with Express 4, as I would like to use Namespaces.
I have worked on some examples of having an Express 4 Server using Socket.io - but most examples are based on one file with everything in it. I am trying to separate all my code to make it easier but I am at a loss as to how to add Socket.io (or where).
I have index.js which uses Cluster and basically calls server.js:
var server = require( "./server.js" );
var cluster = require('cluster');
var webApp={
run: function(){
console.log('Starting: Server');
server.listen();
}
};
if(cluster.isMaster){
cluster.fork();
cluster.on('exit',function(worker){
console.log('Worker ' + worker.id + ' died..');
setTimeout( function () { cluster.fork(); }, 1000 );
});
} else{
try {
webApp.run();
}
catch(e)
{
console.log(e);
process.exit(1);
}
process.on('uncaughtException', function(err){
console.log(err);
process.exit(1);
});
process.on( 'SIGINT', function () {
console.log( "\n SIGINT (Crtl-C)" );
//Kill worker
cluster.disconnect();
process.exit(1);
});
}
This then calls the server.js file:
var path = require('path');
var express = require('express');
var bodyParser = require('body-parser');
var config = require('./config/config.js');
var router = require('./routes');
var Server = Object.subClass({
/**
* Constructor
*/
init:function(){
this.appServer = express();
var that = this;
var appServer = this.appServer;
appServer.use(express.static(__dirname + '/public'));
appServer.set('views', path.join(__dirname, 'views'));
appServer.set('view engine', 'ejs');
appServer.use(bodyParser.urlencoded({ extended: true }));
appServer.use(bodyParser.json());
appServer.get('/',router.root);
},
/**
* Listener HTTP
*/
listen:function(){
var port = config.rest.port;
console.log(':: on port:' + port);
this.appServer.listen(port);
}
});
module.exports = new Server();
I am only having one 'route', which is the '/' and is defined in routes.js file. The page loads fine but where do I add the server side socket.io? and do I add any socket.io namespace definitions in the routes.js file or in the javascript of the page being loaded?
There are so many ways of using sockets that I can't seem to work out the best approach for my multi-file approach.
Any help would be brilliant as I seem to be going in circles.
Enjoy our Saturday :)
Thanks again.
I've spent the morning looking at the Cluster/Worker approach and decided to use 'SocketCluster' as it seems to do what I need.
Enjoy your Sunday
i dont know why im getting this error:
this is my code
/*
Chat application for #node.js
express version.
*/
//Load modules.
var express = require('express'),
socket = require('socket.io'),
swig = require('swig'),
fs = require('fs');
//Load config.
console.log('Loading configuration.');
var config = fs.readFileSync('config.json');
var config = JSON.parse(config);
var port = config.port;
var views = config.views;
console.log('Configuration loaded.');
console.log(config);
//Initiate express module in app.
var app = express();
// app.get('/', function(request, response)
// {
// fs.readFile('./views/index.html', function(error, data)
// {
// if(error)
// {
// response.send('View cannot be rendered.');
// }
// response.type('html');
// response.send(data);
// });
// });
var test = "Hello";
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
swig.setDefaults(
{
cache: false
});
app.get('/', function(request, response)
{
response.render('index',
{
//Var to be named in the render : value;
'test': test,
'Title': 'Testing page',
});
});
//logger.
app.use(function(request, response, next)
{
console.log('%s %s', request.method, request.url);
next();
});
//Set directory for static files (css, js, img)
app.use(express.static(__dirname + '/public'));
//Run the app.
app.listen(port);
it might be some kind of error with the framework itself, but i dont get the clue why, i was using it last night with no error, now im getting this error this morning..
EADDRINUSE means another process is already listening on the same port. Probably this is an earlier run of your server that is still running/crashed and still using the port. Find that process, terminate it, and retry. This is not an error in your javascript code.
Also since you are binding port 80 and running windows, it could be that another web server such as IIS is running and using port 80.
The ports from 0 to 1024 are typically reserved for OS to use. Though its not a thumb rule not to use ports between these limits, its always safe to not use ports in this range to avoid accidental/occassional collision of using port#s.
I would like to use the pretty-error module in my Express app but am having trouble setting it up properly.
I tried using the shortcut...
require('pretty-error').start(function(){
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
});
...but it doesn't work.
I haven't used express before, so I'm not sure if this is the best solution, but this is how I integrated pretty-error with express:
// this is app.js
var express = require('express');
var PrettyError = require('pretty-error');
var app = express();
app.get('/', function(req, res) {
// this will throw an error:
var a = b;
});
var server = app.listen(3000, function(){
console.log('Server started \n');
});
// we can now instantiaite Prettyerror
pe = new PrettyError();
// and use it for our app's error handler
app.use(function(err, req, res, next){
console.log(pe.render(err));
});
// we can optionally configure prettyError to simplify the stack trace:
pe.skipNodeFiles(); // this will skip events.js and http.js and similar core node files
This is the screenshot of the error:
You can also add this if you don't want to see those lines about express` core files:
pe.skipPackage('express');
and this is how it'll look like: