I'm following this tutorial to implement a tic tac toe game using socket.io:
https://ayushgp.github.io/Tic-Tac-Toe-Socket-IO/ .
But I also want to use a login system.
When the user logs in, it successfully goes to this page (I converted html to pug), located on /views/game.pug
doctype html
html
head
title Tic Tac Toe
link(rel='stylesheet', href='/css/main.css')
link(rel='stylesheet', href='/node_modules/skeleton-css/css/skeleton.css')
body
.container
.menu
h1 Tic - Tac - Toe
h3 How To Play
ol
li Player 1 Create a new game by entering the username
li
| Player 2 Enter another username and the room id that is displayed on first window.
li Click on join game.
h4 Create a new Game
input#nameNew(type='text', name='name', placeholder='Enter your name', required='')
button#new New Game
br
br
h4 Join an existing game
input#nameJoin(type='text', name='name', placeholder='Enter your name', required='')
input#room(type='text', name='room', placeholder='Enter Game ID', required='')
button#join Join Game
.gameBoard
h2#userHello
h3#turn
table.center
tr
td
button#button_00.tile
td
button#button_01.tile
td
button#button_02.tile
tr
td
button#button_10.tile
td
button#button_11.tile
td
button#button_12.tile
tr
td
button#button_20.tile
td
button#button_21.tile
td
button#button_22.tile
.container
script(src='/node_modules/jquery/dist/jquery.min.js')
script(src='/socket.io/socket.io.js')
script(src='/js/main2.js')
That works fine. But when I click the button with id #new, nothing happens.
This is the error I get: https://i.imgur.com/83p72Ag.png .
This is the relevant part of main2.js, located on /public/js/main2.js:
$('#new').on('click', () => {
const name = $('#nameNew').val();
if (!name) {
alert('Please enter your name.');
return;
}
socket.emit('createGame', { name });
player = new Player(name, P1);
});
EDIT:
Files' locations:
main.css on /public/css/main.css
skeleton.css on /node_modules/skeleton-css/css/skeleton.css
jquery.min.js on /node_modules/jquery/dist/jquery.min.js
socket.io.js on /node_modules/socket.io-client/dist/socket.io.js
main2.js on /public/js/main2.js
app.js (only relevant parts are shown):
const express = require('express');
const path = require('path');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
app.use(express.static('.'));
//Load View engine
app.engine('pug', require('pug').__express);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
//Set public folder
app.use(express.static(path.join(__dirname, 'public')));
//This get request is sent after the user logs in. It works fine
app.get('/users/game', function(req, res) {
res.render('game', {
title:'Game'
});
});
io.on('connection', (socket) => {
//See full code here:https://github.com/ayushgp/tic-tac-toe-socket-io/blob/master/index.js
}
let articles = require('./routes/articles');
let users = require('./routes/users');
app.use('/articles', articles);
app.use('/users', users);
Also, my main2.js file is identical to this one: https://github.com/ayushgp/tic-tac-toe-socket-io/blob/master/main.js
EDIT2:
Full app.js code (the relevant part is the get request to users/game:
const express = require('express');
const path = require('path');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
const config = require('./config/database');
const passport = require('passport');
let rooms = 0;
app.use(express.static('.'));
mongoose.connect(config.database, {
useMongoClient: true
});
let db = mongoose.connection;
//Check connection
db.once('open', function(){
console.log('Connected to MONGOdb')
});
//Check for DB errors
db.on('error', function(err){
console.log(err);
});
//Bring in models
let Article = require('./models/article');
//Load View Engine
app.engine('pug', require('pug').__express);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// Boddy parser middlware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
//Set public folder
app.use(express.static(path.join(__dirname, 'public')));
//Express Session Middleware
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true,
cookie: { secure: false }
}));
//Express Messages Middleware
app.use(require('connect-flash')());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
//Express Messages Middleware
app.use(expressValidator());
//Passport Config
require('./config/passport')(passport);
//Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
app.get('*', function(req, res, next){
res.locals.user = req.user || null;
next();
});
//Home ROute
app.get('/', function(req, res) {
Article.find({}, function(err, articles){
if(err){
console.log(err);
} else {
res.render('index', {
title:'Articles',
articles: articles
});
}
});
});
app.get('/users/game', function(req, res) {
res.render('game', {
title:'Game'
});
});
io.on('connection', (socket) => {
// Create a new game room and notify the creator of game.
socket.on('createGame', (data) => {
socket.join(`room-${++rooms}`);
socket.emit('newGame', { name: data.name, room: `room-${rooms}` });
});
// Connect the Player 2 to the room he requested. Show error if room full.
socket.on('joinGame', function (data) {
var room = io.nsps['/'].adapter.rooms[data.room];
if (room && room.length === 1) {
socket.join(data.room);
socket.broadcast.to(data.room).emit('player1', {});
socket.emit('player2', { name: data.name, room: data.room })
} else {
socket.emit('err', { message: 'Sorry, The room is full!' });
}
});
/**
* Handle the turn played by either player and notify the other.
*/
socket.on('playTurn', (data) => {
socket.broadcast.to(data.room).emit('turnPlayed', {
tile: data.tile,
room: data.room
});
});
/**
* Notify the players about the victor.
*/
socket.on('gameEnded', (data) => {
socket.broadcast.to(data.room).emit('gameEnd', data);
});
});
//Route files
let articles = require('./routes/articles');
let users = require('./routes/users');
app.use('/articles', articles);
app.use('/users', users);
//Start Sever
app.listen(3000, function() {
console.log('Server running');
});
The code block will not working:
script(src='node_modules/jquery/dist/jquery.min.js')
please try like this:
app.use('/scripts',
express.static(path.join(__dirname, 'node_modules/jquery/dist')),
// add some others
);
app.use('/styles',
express.static(path.join(__dirname, '/node_modules/skeleton-css/css')),
// add some others
);
On view:
script(src='/scripts/jquery.min.js')
link(type='text/stylesheet' href='/styles/skeleton.css')
And you don't need the socket-io-client module for socket client.
On your code block, if you want the socket connection of the same original host, you don't need the socket-io-client module.
if you have created the socket server using socket.io, you can include the socket.io script like this when using view template.
script(type='text/javascript', src='/socket.io/socket.io.js')
Based on your console screen grab, there are at least two problems here:
Your server-side route (if you even have one) for script(src='node_modules/jquery/dist/jquery.min.js') is not working so jQuery never loads in the web page. Thus, no attempt to use jQuery works.
Your socket.io server is not started or initialized properly on the server.
To be able to suggest fixes, we'd need to see the relevant server-side code and we'd need to know where all resources referenced in game.pug are located in your server-side file system (full path). You are either missing route a definition for the jQuery file or there's an error in the route definition.
It does look like main2.js is loading properly, though it immediately encounters an error because of the missing jQuery.
FYI, using script paths like this:
script(src='/node_modules/jquery/dist/jquery.min.js')
is generally not considered a good practice because it exposes and ties you to a specific server-side file structure. In general, you would do something like this instead:
app.use("/jquery", express.static(path.join(__dirname, "/node_modules/jQuery/dist")));
And, then use this in the client:
script(src='/jquery/jquery.min.js')
Now, the ONLY directory you've exposed to the public is /node_modules/jQuery/dist and you've not created a hard link between client web pages and server-side file structure.
You would repeat that process for each dist directory that you need to draw from. The way you have it now, you have granted public access to your entire node_modules server-side directory which is NOT something you want to do.
Also, when your socket.io server is working appropriately on the server, then it has a built-in route for socket.io.js. You can just use this in the client:
script(src='/socket.io/socket.io.js')
And, the socket.io server will automatically server the socket.io.js from that route. You don't have to manually create a route for that.
To get socket.io working properly, change this;
//Start Sever
app.listen(3000, function() {
console.log('Server running');
});
to this:
//Start Sever
server.listen(3000, function() {
console.log('Server running');
});
In these two lines of code, you created a web server and bound socket.io to it:
const server = require('http').Server(app);
const io = require('socket.io')(server);
But, then with app.listen(), you created a different web server and started it and never started the one that socket.io is connected to. Instead, you want to use server.listen(...) to start the one that you attached socket.io to.
Related
enter code here
//Here is my app.js code, I want to make a basic routing navigation bar, here demo is my file name. I want to insert some HTML into the demo page but got nothing on the browser screen
const path = require("path");
const app = express();
const port = 80;
// For serving static files
app.use("/static", express.static("static"));
// Set the template engine as pug
app.set("view engine", "pug");
// Set the views directory
app.set("views", path.join(__dirname, "views"));
// Our pug demo endpoint
app.get("/demo", (req, res) => {
res
.status(200)
.render("demo", {
title: "Hey Harry",
message: "Hello there and thanks for telling me how to use pubG!",
});
});
app.get("/", (req, res) => {
res.status(200).send("This is homepage of my first express app with Harry");
});
app.get("/about", (req, res) => {
res.send("This is about page of my first express app with Harry");
});
app.post("/about", (req, res) => {
res.send(
"This is a post request about page of my first express app with Harry"
);
});
app.get("/this", (req, res) => {
res.status(404).send("This page is not found on my website cwh");
});
app.listen(port, () => {
console.log(`The application started successfully on port ${port}`);
});```
enter code here
//& Here is my code for demo.pug
```html
head
title=title
body
h1 = message```
Please remove the backticks at the end of your file,
Please include this line in your file: const express = require("express");
You can use EJS instead of pug. It is more popular and easier to write and understand.
Assuming you have views folder at the root, you can delete this line:
// Set the views directory
app.set("views", path.join(__dirname, "views"));
Adding one more res will make your code look more stylish and also less buggy (For instance, message line shouldn't have comma at the end):
app.get("/demo", (req, res) => {
res.status(200);
res.render("demo", {
title: "Hey Harry",
message: "Hello there and thanks for telling me how to use pubG!"
});
});
I checked the your code on my computer and it worked. Please try the steps above and let me know if it works.
I've been trying to implement a paymentCtrl to handle the Stripe payments but am unable to get the express to work. When i execute this code i get the following error below. I'm quite new to this and would like to understand why i get this error.
error:
Unknown provider: appProvider <- app <- paymentCtrl
app.js:
angular.module('userApp', ['appRoutes', 'userControllers', 'userServices', 'ngAnimate', 'mainController', 'authServices', 'managementController', 'paymentController'])
.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptors');
});
payment.html:
<div>
<form action="/charge" method="post">
<script
src="https://checkout.stripe.com/checkout.js"
class="stripe-button"
data-key="pk_test_..."
data-amount="3000"
data-name="walla"
data-description="this is not a dog"
data-locale="auto"
data-currency="gbp"
></script>
</script>
</form>
</div>
paymentCtrl:
angular.module('paymentController', [])
.controller('paymentCtrl', function(app, passport) {
app.post('/charge', function(req, res){
});
});
server.js:
var express = require('express'); // ExperssJS Framework
var app = express(); // Invoke express to variable for use in application
var port = process.env.PORT || 8080; // Set default port or assign a port in enviornment
var morgan = require('morgan'); // Import Morgan Package
var mongoose = require('mongoose'); // HTTP request logger middleware for Node.js
var bodyParser = require('body-parser'); // Node.js body parsing middleware. Parses incoming request bodies in a middleware before your handlers, available under req.body.
var router = express.Router(); // Invoke the Express Router
var appRoutes = require('./app/routes/api')(router); // Import the application end points/API
var path = require('path'); // Import path module
var passport = require('passport'); // Express-compatible authentication middleware for Node.js.
var social = require('./app/passport/passport')(app, passport); // Import passport.js End Points/API
var stripe = require('stripe')('sk_test_...');
app.use(morgan('dev')); // Morgan Middleware
app.use(bodyParser.json()); // Body-parser middleware
app.use(bodyParser.urlencoded({ extended: true })); // For parsing application/x-www-form-urlencoded
app.use(express.static(__dirname + '/public')); // Allow front end to access public folder
app.use('/api', appRoutes); // Assign name to end points (e.g., '/api/management/', '/api/users' ,etc. )
//
// <---------- REPLACE WITH YOUR MONGOOSE CONFIGURATION ---------->
//
mongoose.connect('mongodb://localhost:27017/tutorial', function(err) {
if (err) {
console.log('Not connected to the database: ' + err);
} else {
console.log('Successfully connected to MongoDB');
}
});
// Set Application Static Layout
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/app/views/index.html')); // Set index.html as layout
});
// Start Server
app.listen(port, function() {
console.log('Running the server on port ' + port); // Listen on configured port
});
Your angular controller should be injected with $http module, app is undefined in your client side code as client side would not inherit code from your server.
$http module contains .post method along side numerous other methods such as .get .put .delete etc.
angular.module('paymentController', [])
.controller('paymentCtrl', function(app, passport, $http) {
$http.post('/charge', {}, function(req, res){
});
});
The second parameters in the $http.post ({}) is the data you want to transmit to your controller.
Lastly, you need a server method which will retrieve the POST request.
app.post('/charge', function(req, res) {
// Your server endpoint for /charge POST action
// req.body contains passed data.
});
As you're trying to send data using Angular to your server, you'll need to bind the form data to your model, and remove the form or listen to form submit event and make a POST request yourself the way you want to.
As you have not included the whole HTML document, it is hard to see if there are any other errors included, such as missing ng-controller declaration in your document as comments stated.
I assume you followed this Stripe tutorial so all you need to do is:
The code you've written in paymentCtrl should be copied into server.js before app.listen
// Set Application Static Layout
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/app/views/index.html')); // Set index.html as layout
});
app.post('/charge', function(req, res){});
// Start Server
app.listen(port, function() {
console.log('Running the server on port ' + port); // Listen on configured port
});
Unknown provider: appProvider <- app <- paymentCtrl
This means that app variable you are trying to inject does not exist in your client side code.
I am building an api that will interface with the MongoDB database and have mounted it as a subapplication. I have defined a session variable in my server controller.
However, any time that the server files need to talk to the api files the session variables are never passed off.
Heres the app.js file
//app.js file
'use strict';
process.env.NODE_ENV = 'development';
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var flash = require('connect-flash');
var helmet = require('helmet');
var app = express();
app.use(helmet());
var port = process.env.PORT || 3000;
mongoose.connect("mongodb://localhost:27017/striv4");
var db = mongoose.connection;
// mongo error
db.on('error', console.error.bind(console, 'connection error:'));
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: false,
store: new MongoStore({
mongooseConnection: db
})
}));
app.use(flash());
// make user ID available in templates
app.use(function (req, res, next) {
res.locals.currentUser = {
username:req.session.username,
id: req.session.userId
};
next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secreter'));
app.use(logger('dev'));
var api = require('./app_api/routes/index');
var serverRoutes = require('./server/routes/index');
//static file middleware
app.use(express.static(__dirname + '/public'));
app.set('views',__dirname +'/server/views');
app.set('view engine','pug');
app.use('/',serverRoutes);
app.use('/api',api);
//custom error handler
app.use(function(error, req, res, next) {
res.status(error.status || 500);
res.send('Error: '+error.message);
});
app.listen(port);
console.log('Listening on port: '+port);
You've got the whole program listed so there is more than one way for this to have gone wrong. Here are my suggestions to fix this:
Check the version of express-session you've installed. (Just run npm ls in the terminal and in your root Node app folder where you're package.json file is). If it's equal to or greater than v1.5.0, you don't need the cookie-parser for sessions anymore. Comment out the app.use line for the cookie parser and see if this works.
If you still need cookie parser for some other reason, you should use the same secret for sessions and the cookie parser. In your code, you've set two different values for secret.
I've seen that the other big failure for sessions occurs if the session store is not correctly connected to your Node app. Cross-check that the database is available and working. In my experience, Express sessions will fail silently if it can't get to the DB.
Hope this helps.
I have a simple example that I am following.
For some reason the request always times out, wondering if you have any ideas why this could be happening.
// server.js
// BASE SETUP
// =============================================================================
// call the packages we need
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080; // set our port
//load the model
var Bear = require('./models/bear');
// ROUTES FOR OUR API
// =============================================================================
var router = express.Router(); // get an instance of the express Router
// middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
next(); // make sure we go to the next routes and don't stop here
});
router.route('/bears')
// create a bear (accessed at POST http://localhost:8080/api/bears)
.post(function(req, res) {
var bear = new Bear(); // create a new instance of the Bear model
bear.name = req.body.name; // set the bears name (comes from the request)
// save the bear and check for errors
bear.save(function(err) {
if (err)
res.send(err);
//res.json({ message: 'Bear created!' });
res.json({ message: 'hooray! welcome to our api!' });
});
});
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
// more routes for our API will happen here
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
Let me know what you think. Essentially I can do GETS no problem, but when I get to /bears and do a POST x-www-form-urlencoded with a param name 'Klaus' it simply hangs. I can't understand why.
Any suggestions much appreciated.
Many thanks for your help.
Does anybody know how to fetch images from node.js server's folder in URL?
In my folder structure I have folder data and inside there is subfolder img with image. I want to access this image with URL, like this:
http://localhost:3000/data/img/default.jpg
but when I enter it into browser I always get this error:
Page Not Found /data/img/default.jpg is not a valid path.
server.js:
'use strict';
/**
* Module dependencies.
*/
var init = require('./config/init')(),
config = require('./config/config'),
mongoose = require('mongoose');
var express = require('express');
/**
* Main application entry file.
* Please note that the order of loading is important.
*/
// Bootstrap db connection
var db = mongoose.connect(config.db, function(err) {
if (err) {
console.error('\x1b[31m', 'Could not connect to MongoDB!');
console.log(err);
}
});
// Init the express application
var app = require('./config/express')(db);
// Bootstrap passport config
require('./config/passport')();
app.use(express.static('data/img'));
// Start the app by listening on <port>
app.listen(config.port);
// Expose app
exports = module.exports = app;
// Logging initialization
console.log('MEAN.JS application started on port ' + config.port);
express.js:
'use strict';
/**
* Module dependencies.
*/
var express = require('express'),
morgan = require('morgan'),
bodyParser = require('body-parser'),
session = require('express-session'),
compress = require('compression'),
methodOverride = require('method-override'),
cookieParser = require('cookie-parser'),
helmet = require('helmet'),
passport = require('passport'),
mongoStore = require('connect-mongo')({
session: session
}),
flash = require('connect-flash'),
config = require('./config'),
consolidate = require('consolidate'),
path = require('path');
module.exports = function(db) {
// Initialize express app
var app = express();
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
// Setting application local variables
app.locals.title = config.app.title;
app.locals.description = config.app.description;
app.locals.keywords = config.app.keywords;
app.locals.facebookAppId = config.facebook.clientID;
app.locals.jsFiles = config.getJavaScriptAssets();
app.locals.cssFiles = config.getCSSAssets();
// Passing the request url to environment locals
app.use(function(req, res, next) {
res.locals.url = req.protocol + '://' + req.headers.host + req.url;
next();
});
// Should be placed before express.static
app.use(compress({
filter: function(req, res) {
return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
},
level: 9
}));
// Showing stack errors
app.set('showStackError', true);
// Set swig as the template engine
app.engine('server.view.html', consolidate[config.templateEngine]);
// Set views path and view engine
app.set('view engine', 'server.view.html');
app.set('views', './app/views');
// Environment dependent middleware
if (process.env.NODE_ENV === 'development') {
// Enable logger (morgan)
app.use(morgan('dev'));
// Disable views cache
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
app.locals.cache = 'memory';
}
// Request body parsing middleware should be above methodOverride
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
// Enable jsonp
app.enable('jsonp callback');
// CookieParser should be above session
app.use(cookieParser());
// Express MongoDB session storage
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret,
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// use passport session
app.use(passport.initialize());
app.use(passport.session());
// connect flash for flash messages
app.use(flash());
// Use helmet to secure Express headers
app.use(helmet.xframe());
app.use(helmet.xssFilter());
app.use(helmet.nosniff());
app.use(helmet.ienoopen());
app.disable('x-powered-by');
// Setting the app router and static folder
app.use(express.static(path.resolve('./public')));
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
// Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
console.error(err.stack);
// Error page
res.status(500).render('500', {
error: err.stack
});
});
// Assume 404 since no middleware responded
app.use(function(req, res) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not Found'
});
});
return app;
};
It's like you have already set your data/img folder as a static folder in the line below:
app.use(express.static('data/img'));
In that case, you should be accessing images placed in the static folder above using below url:
http://localhost:3000/default.jpg
I will however advice you use Node's global variable __dirname to indicate the root of the static folder but this depends on where your server.js is located within your file structure.
The js file containing the snippets below is located in the root and I have /data/img folder from the root as well and I am able to retrieve the image using /image name.
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/data/img'));
app.listen(3500, function () {
console.log('Express server is listening, use this url - localhost:3500/default.png');
});
See if this helps you. If it does, make sure you know the reason for using the __dirname global variable name.
SO1