I'm approaching to this framework for node.js for several reasons. Simplicity, great modularity and a fast configuration out of the box. I have soon encountered the concept of Pack which I have never seen during my experience in the learning of express.js framework. From the official guide the following example:
var Good = require('good');
server.pack.register(Good, function (err) {
if (err) {
throw err; // something bad happened loading the plugin
}
server.start(function () {
server.log('info', 'Server running at: ' + server.info.uri);
});
});
They says about Pack:
Packs are a way for hapi to combine multiple servers into a single
unit, and are designed to give a unified interface when working with
plugins.
This concept is weird for me. How many times do we work with different servers in a project? In addition is not clear for me whether I should call pack every time to register a plugins in hapi.
Update: This is pre v8 api code, the way to register a plugin has been changed. (call register directly on the server)
This concept is weird for me. How many times do we work with different servers in a project?
One example is when you have an api and a web server. These are usually developed separately, often in separate repositories. You could then create a third project which combines these plugins:
var Hapi = require('hapi');
var manifest = {
servers: [
{
host: 'localhost',
port: 8000,
options: {
labels: 'api',
cors: true
}
},
{
host: 'localhost',
port: 8001,
options: {
labels: 'web'
}
}
],
plugins: {
'./example-api': [{select: 'api'}],
'./example-web': [{select: 'web'}]
}
};
Hapi.Pack.compose(manifest, function(err, pack) {
pack.start();
});
In addition is not clear for me whether I should call ever time pack to register a plugins in hapi.
Yes, you need to call pack.register() when you want to register a plugin. However you can register more plugins at once:
plugin.register([
require('crumb'),
require('hapi-auth-cookie')
], function (err) {
// Error handling
}
Visit Link: http://cronj.com/blog/hapi-mongoose
Sample Project which can help you Repo Link: https://github.com/gauravgupta90/Hapi-Mongoose-Angular
For hapi version earlier than 8.x
var server = Hapi.createServer(host, port, {
cors: true
});
server.start(function() {
console.log('Server started ', server.info.uri);
});
For hapi new version
var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({ port: app.config.server.port });
Hapi.Pack() is no longer available in the newest versions of Hapi (8.x). They have pulled the functionality out into a small library called Glue. You can find it here: https://github.com/hapijs/glue. It works exactly how Hapi.Pack() used to.
By default, hapi supports multiple connections and you can customize them individually, like installing plugins only for a selected server (like API only).
You can instantiate and kick off multiple connection like this:
const hapi = require('hapi');
const port = 3000;
const _ = require('lodash');
// Create hapi server instance
const server = new hapi.Server();
// add connection parameters
server.connection({
host: 'localhost',
port: process.env.PORT || port
});
server.connection({
host: 'localhost',
port: process.env.PORT + 1 || port + 1
});
// Start the server
server.start(function () {
// Log to the console the host and port info
_.forEach(server.connections, function(connection) {
console.log('Server started at: ' + connection.info.uri);
});
});
Hope that helps.
If you need more details about that topic, you can find them within this tutorial on how to run separate frontend and backend servers within a single project
Related
in the local LAN everything is working very well, but over the internet it doesn't work.
i read a lot about WebRTC Signaling.
i use the following node.js peerjs server
whats wrong with my config?
var fs = require('fs');
var PeerServer = require('peer').PeerServer;
var server = PeerServer({
port: 3001,
debug: true,
path: '/peerjs',
ssl: {
key: fs.readFileSync('privkey.pem', 'utf8'),
cert: fs.readFileSync('fullchain.pem', 'utf8')
},
config: {'iceServers': [
{ url: 'stun:stun.l.google.com:19302' },
]}
});
First of all, you need to use a PeerServer that is not on your local network (=accessible to the internet). There is one provided by peer.js, which is used by default when no PeerServer URL is specified by the client.
To establish a connection, a library like socket.io can be very useful. This video gives a good explanation: https://www.youtube.com/watch?v=DvlyzDZDEq4
Here is the problem. When I load the page in the browser and check to see if my "test" was emitted, I run into this wall of spamming polling.
The code I use is exactly the same as in other projects I have done, so it makes no sense to me that this doesn't work now. -_-
app.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 8000;
server.listen(port, function(){
console.log('server ready - listening on *:8000');
});
app.get( '/*' , function( req, res, next ) {
//This is the current file they have requested
var file = req.params[0];
//Send the requesting client the file.
res.sendFile( __dirname + '/' + file );
});
io.on('connection', function (socket) {
socket.on('test', function(){
console.log("test worked");
});
});
client.js
var socket = io();
socket.emit("test");
I broke the code down to what you see above. There's nothing else. And it doesn't work. internal screaming
I'll post my comment as an answer so you can wrap up this question. One common reason that socket.io will loop with http requests and never successfully connect is if you are running mismatched version on the client and server. This seems to have happened recently with socket.io upon a recent version change so they must have made some change in how the connection logic works that makes it fail to connect if versions are mismatched.
If you load your client via this:
<script src="/socket.io/socket.io.js"></script>
Then, the client will always match the server version as long as you don't have any other <script> tags that are loading some other version of socket.io.
One more solution which worked for me ( Socket.IO 2.3.0 and Socket.IO Client 2.3.0 ) is to set the transports field when you create the instance of io on back-end and socket on front-end , like this :
On back-end :
io = require('socket.io')(http,{
log: false,
agent: false,
origins : '*:*' , // this is for the CORS browser error , I also use the cors npm module here
transports : [ 'websocket' ]
});
And on front-end :
const socket = socketIOClient(url,{
forceNew : false ,
secure : true ,
transports: [ 'websocket' ]
});
Hope it helps , if not the question owner , then maybe the others :)
What would be the best way to store DB config (username, password) in an open source app that runs on node.js / Express? Two specific questions:
Shall I put it into a separate config.js file in /lib folder, for example, and never include it into the master repository that is publicly available on GitHub?
To inlcude the config, is it as simple as require('./config.js') from the file that needs it or is there a better way of doing it?
PS sorry if the questions seem a bit simple or not so well formulated, but I'm just starting :)
Here's how I do it:
Create a config.js which contains objects representing your configs:
var config = {
development: {
//url to be used in link generation
url: 'http://my.site.com',
//mongodb connection settings
database: {
host: '127.0.0.1',
port: '27017',
db: 'site_dev'
},
//server details
server: {
host: '127.0.0.1',
port: '3422'
}
},
production: {
//url to be used in link generation
url: 'http://my.site.com',
//mongodb connection settings
database: {
host: '127.0.0.1',
port: '27017',
db: 'site'
},
//server details
server: {
host: '127.0.0.1',
port: '3421'
}
}
};
module.exports = config;
Then in my index.js (or wherever really),
var env = process.env.NODE_ENV || 'development';
var config = require('./config')[env];
Then process with that object, e.g.
var server = express();
server.listen(config.server.port);
...
For running toy apps where I need to hide db credentials, I use the dotenv module.
Place your sensitive info in a .env file (which is .gitignored), place require('dotenv').config(); in your app; dotenv creates entries in process.env that you can refer to.
.env file:
DATABASE_PASSWORD=mypw
DATABASE_NAME=some_db
To refer to the values:
process.env.DATABASE_PASSWORD
Not sure whether this is the best practice, but personally I have a config.json file where I store my db connection information. Then I do the following:
// options.js
var fs = require('fs'),
configPath = './config.json';
var parsed = JSON.parse(fs.readFileSync(configPath, 'UTF-8'));
exports.storageConfig= parsed;
Then from a different file I do the following:
var options = require('./options');
var loginData = {
host: options.storageConfig.HOST,
user: options.storageConfig.user,
password: options.storageConfig.password
};
I do put in args. just like the port of so many node.js example.
you most likely forever, pm2, nodemon to run your app. so this variable is not check in as part of your source code. and they are globally available too.
process.env.PORT
process.env.DATABASE_USER
process.env.DATABASE_PASSWORD
PORT=3000 DATABASE_HOST=localhost DATABASE_USER=admin DATABASE_PASSWORD=mypassword node app.js
export PORT=3000
export DATABASE_HOST=localhost
export DATABASE_PORT=27017
export DATABASE_USER=admin
export DATABASE_PASSWORD=mypassword
node app.js
var server = app.listen(process.env.PORT, function() {
});
var mongoClient = new MongoClient(new Server(process.env.DATABASE_HOST, process.env.DATABASE_PORT));
To inlcude the config, is it as simple as require('./config.js') from the file that needs it or is there a better way of doing it?
This is the right way to store config files.
The best approach would be to write your entire application like an ordinary node.js module, and write a small start-up file that calls it. This idea also allow you to use different database drivers using dependency injection.
Good, but not perfect solution is the environment. It is shared among all application, so if you have certain data you want to be available to all of them, this is the best bet. But if you have a config for one particular app, not much so.
PS: And please, don't use JSON for this. It's the worst idea possible. :)
I found this a nice way to handle my config, considering different environments:
config.coffee
exports.setEnvironment = (env) ->
switch env
when "development"
exports.DEBUG_LOG = true
exports.DB_PORT = '27017'
# ...
when "testing"
exports.DEBUG_ERROR = true
exports.DEBUG_CLIENT = true
# ...
when "production"
exports.DEBUG_LOG = false
# ...
else console.log "environment #{env} not found"
server.coffee:
config = require('./config')
config.setEnvironment env
Using environment variables
You can use export to set environment variables in OSX and Linux. The following is an example of setting a value in the SESSION_SECRET key.
export SESSION_SECRET="keyboard cat"
In Windows, you can use set.
set SESSION_SECRET="keyboard cat"
You can also set environment variables each time you run them.
SESSION_SECRET="keyboard cat" node secret-env.js
Use process.env of node.js to access environmental variables within code.
var express = require('express')
var session = require('express-session')
var app = express()
app.use(session({secret: process.env.SESSION_SECRET}))
Request a argument from the command-line
The best way to protect confidential information is not to store it in a setup file.
If the command-line requests configuration information as an argument using the noopt package, the secret information does not need to exist as a file.
The following is an example of requesting a session key as an argument using the noopt package.
var nopt = require("nopt")
var longOpts = {
"sessionSecret": String,
}
var shortOpts = {
"s": ["--sessionSecret"],
}
var parsed = nopt(longOpts, shortOpts, process.argv, 2)
console.log("session secret is:", parsed.sessionSecret)
node secret-arg.js --sessionSecret "keyboard cat"
node secret-arg.js -s "keyboard cat"
Advantages : It is safer to expose confidential information than to hardcoding or having it as a configuration file.
Disadvantages : There is a hassle of increasing the amount of information to be entered each time the app is launched.
If you try to create and solve a script, the problem that the password still exists in the script remains.
How to do socket.io implementation in Webrtc Video calling?
A little bit overload but it works: SocialVidRTC
I understand from your question that you already have a WebRTC project and some signalling mechanism in server.js , possibly websockets .
To replace this with socket.io or any other signalling as SIP / XHR / AJAX etc , you need to replace server.js with new socket.io based code for request and response .
Follow these steps :
create a https server ( since webrtc pages capture web cam input only from secure origins) for socket.io. Assign server to an variable say app.
var fs = require('fs');
var https = require('https');
var options = {
key: fs.readFileSync('ssl_certs/server.key'),
cert: fs.readFileSync('ssl_certs/server.crt'),
ca: fs.readFileSync('ssl_certs/ca.crt'),
requestCert: true,
rejectUnauthorized: false
};
var app = https.createServer(options, function(request, response){
request.addListener('end', function () {
file.serve(request, response);
}).resume();
});
app.listen(8081);
here server.key , server.crt and ca.crt are fake ssl certs and 8081 is the https port I have selected .
you can reuse the same https server for hosting the webpages also.
listen on this same port for socket.io using app defined earlier
var io = require('socket.io').listen(app, {
log: false,
origins: '*:*'
});
io.set('transports', [
'websocket'
]);
I choose only websocket but you can set other types of transport too such as
socket.set('transports', [
'websocket'
, 'flashsocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
Now implement signalling specific functions and calls such as ,
io.sockets.on('connection', function (socket) {
...
socket.on('webrtc-joinchannel',function(data){
var resp=joinChannel(data);
socket.emit('resp-webrtc-joinchannel', resp);
});
...
});
Note : I am using socket.io v0.9 .
If yo want a example implementation you can view any sample projects such as here
I setup Yeoman 1.0 beta to handle my js/css tasks. Everything works fine that, if I run grunt server, it starts up a static server and connects a browser session to port 9000 (livereload). js/css concat, minification are also working.
Now, is there a way I can make it to connect to a google app engine development server (instead of starting a static server). The server is running at port 8080 on localhost, and I want grunt to reload the webpage upon css/js files under watch. These files would be served by GAE server.
I see a section rolling your own at grunt-contrib-connect documentation, but not sure it means an external server. As far as I see, these are the relavent configuration from Gruntfile.js
connect: {
livereload: {
options: {
port: 8080, //*** was 9001 originally **
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app)
];
}
}
},
When I change the port number to 8080, and try to start, obviously it gives error.
Fatal error: Port 8080 is already in use by another process.
so, I don't want to start a new server, but connect through GAE server already running.
Thanks.
In order to use GAE server instead of nodejs server, we need to do the following.
* Compile your less/coffeescript, concat[, minify], copy your code to the location where the app engine code resides.
* Create a task in grunt.js to spawn a shell command to run app engine.
This is the example, that I used as reference. https://github.com/cowboy/grunt/tree/master/tasks
Following grunt.js file may help!
module.exports = function(grunt) {
grunt.initConfig({
....
});
grunt.registerTask('appengine-update', 'Upload to App Engine.', function() {
var spawn = require('child_process').spawn;
var PIPE = {stdio: 'inherit'};
var done = this.async();
spawn('appcfg.py', ['update', 'build/task-manager-angular'], PIPE).on('exit', function(status) {
done(status === 0);
});
});
grunt.registerTask('clean', 'Clean the whole build directory.', function() {
require('child_process').exec('rm -rdf build', this.async());
});
grunt.registerTask('run', 'Run app server.', function() {
var spawn = require('child_process').spawn;
var PIPE = {stdio: 'inherit'};
var done = this.async();
spawn('dev_appserver.py', ['.'], PIPE).on('exit', function(status) {
done(status === 0);
});
});
});
//....
//Other settings
//....
grunt.loadTasks('tasks');
grunt.loadNpmTasks('grunt-coffeelint');
grunt.registerTask('build', 'coffee less concat');
grunt.registerTask('deploy', 'coffee less concat build appengine-update');
grunt.registerTask('default', 'coffee less');
};
Found this Google App Engine management plugin for Grunt