error to use soket.io module in mvc express app - node.js

I want to use soket.io in my app and use module.export for mvc express app.
May server code is:
var express = require('express')
, app = express()
, router = express.Router();
var http= require('http').Server(app);
var io=require('socket.io')(http);
app.io = require('socket.io')();
...
//api
app.use(require('./controllers'));
app.listen(config.port, function() {
console.log('Listening on port ' + config.port)})
And my controllers/ index :
var express = require('express')
, router = express.Router();
..
router.get('/', function(req, res) {
res.send('hi')
});
router.use('/chat', require('./chat'));
module.exports = router
</code>
My chat.js file is:
var app = require('express')
, chat = app.Router();
var http= require('http').Server(app);
var io = require('socket.io')(http);
var path = require("path");
chat
.get('/', function(req, res) {
let reqPath = path.join(__dirname, '../');
// res;
io.on('connection', function(socket){
console.log('a user connected');
})
res.sendFile(reqPath +'/views/index.html'); })
io.on('connection', function(socket){
console.log('a user connected');
});
The code send my html file and show my result. But don't show console.log('a user connected'); in my console.

<code><!DOCTYPE html>
<html>
<head>
<title>Hello world</title>
</head>
<script src = "/socket.io/socket.io.js"></script>
<script>
var socket = io();
function sendMessage() {
var msg = document.getElementById('message').value;
if(msg) {
socket.emit('msg',msg);
}
}
socket.on('msg', function(data) {
document.getElementById('message-container').innerHTML += '<div>' + data.ChatMessage + '</div>'
})
</script>
<body>
<div id = "error-container"></div>
<input type = "text" id = "message">
<button type = "button" name = "button" onclick = "sendMessage()">Send</button>
<div id = "message-container"></div>
</body>
</html></code>

Related

Socket.io: io.on('connection) repeats three times

The following is an excerpt from some server side code located in the entry point of the application:
const app = express()
const chatServer = require('http').Server(app);
chatServer.listen(3000)
const io = require('socket.io')(chatServer);
io.on('connection', (socket) => {
console.log('ABC')
socket.on('send-chat-message', message => {
socket.broadcast.emit('chat-message', message)
})
});
Upon running my dev server I expected to see 'ABC' print once to the console. However, it is printing three times (ABC, ABC, ABC) instead. Why does this happen? The io variable is NOT used anywhere else in the application. I'm pretty sure it has nothing to do with client side logic (since no requests are made by the client at this point) And for complete reference, the entire app.js code is displayed below:
const express = require('express')
require('./db/mongoose')
const playerRouter = require('./routers/player')
const contractRouter = require('./routers/contract')
const bodyParser = require('body-parser');
const hbs = require('express-handlebars')
const path = require('path')
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
// Define paths for Express config
const viewsPath = path.join(__dirname, '../templates/views')
const partialsPath = path.join(__dirname, '../templates/partials')
const layoutPath = path.join(__dirname, '../templates/layouts')
const app = express()
const chatServer = require('http').Server(app);
chatServer.listen(3000)
const io = require('socket.io')(chatServer);
// Passport Config
require('./middleware/passport')(passport);
//Setup handlebars engine and views location
app.engine('hbs', hbs({
extname: 'hbs',
defaultLayout: 'main',
layoutsDir: layoutPath,
partialsDir: partialsPath,
}));
app.set('view engine', 'hbs')
app.use(express.static('public'))
app.set('views', viewsPath)
io.on('connection', (socket) => {
console.log('ABC')
socket.on('send-chat-message', message => {
socket.broadcast.emit('chat-message', message)
})
});
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json())
// Express session
app.use(
session({
secret: 'secret',
resave: true,
saveUninitialized: true
})
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Connect flash
app.use(flash());
// Global variables
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.currentUser = req.user
next();
});
app.use(playerRouter)
app.use(contractRouter)
module.exports = app
Here is the client side code (for brevity I did not include the entire HTML file):
const socket = io('http://localhost:3000')
const messageContainer = document.getElementById('message-container')
const messageForm = document.getElementById('send-container')
const messageInput = document.getElementById('message-input')
socket.on('chat-message', message => {
appendMessage(`Opponent: ${message}`)
})
messageForm.addEventListener('submit', e => {
e.preventDefault()
const message = messageInput.value
appendMessage(`You: ${message}`)
socket.emit('send-chat-message', message)
messageInput.value = ''
})
const appendMessage = (message) => {
const messageElement = document.createElement('div')
messageElement.innerText = message
messageContainer.append(messageElement)
}
Sure, the message 'ABC' is rendered every time a connection to the client is established.
const express = require("express");
const path = require("path");
const app = express();
const http = require("http").Server(app);
const io = require("socket.io")(http);
// Here declare fiel static, as index.html, css, javascript.
app.use(express.static(path.resolve(__dirname, "../public")));
io.on("connection", socket => {
console.log("ABC");
socket.on("send-chat-message", message => {
socket.broadcast.emit("chat-message", message);
});
});
http.listen(8080, () => {
console.log("Starting...");
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="message-container"></div>
<form id="send-container">
<input id="message-input" type="text" />
<button type="submit">submit</button>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script>
const socket = io();
const messageContainer = document.getElementById("message-container");
const messageForm = document.getElementById("send-container");
const messageInput = document.getElementById("message-input");
socket.on("chat-message", message => {
appendMessage(`Opponent: ${message}`);
});
messageForm.addEventListener("submit", e => {
e.preventDefault();
const message = messageInput.value;
console.log(message);
appendMessage(`You: ${message}`);
socket.emit("send-chat-message", message);
messageInput.value = "";
});
const appendMessage = message => {
const messageElement = document.createElement("div");
messageElement.innerText = message;
messageContainer.append(messageElement);
};
</script>
</body>
</html>
Here you can see the code working live.
I hope it helps. Any questions comment.
https://codesandbox.io/s/expressjs-chat-9v8lo

Node.js how to use socket.io in express route

In one of my node.js script i am trying to use socket.io in express route. I found many similar questions and tried to implement the solution as suggested but nothing worked out. May be because of my lack of understanding of express routes. I followed below links,
How use socket.io in express routes with node.js
Use socket.io in expressjs routes instead of in main server.js file
This is my app.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
const PORT = 3000;
server.listen(PORT);
console.log('Server is running');
var api = require('./routes/api');
//app.use('/api', api);
app.use('/api', (req, res) => {
res.sendFile(__dirname + '/api.html');
});
app.get('/', (req, res) => {
res.send("this is home location");
});
And route file api.js in ./routes folder
var express = require('express');
var router = express.Router();
var fs = require("fs");
var bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
console.log("inside api route");
router.get('/', function(req, res, next) {
console.log("api route called");
const connections = [];
var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
io.sockets.on('connection',(socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
socket.emit('server message', jsonobj);
});
//res.send(jsonobj)
});
module.exports = router;
Socket.emit is not showing data on html page i am rendering on route use. My html code is,
//api.html
<!DOCTYPE html>
<html lang="en">
<body>
<div class="container">
<h1 class="jumbotron">
Node js Socket io with socket route example
</h1>
<div class="results">results</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script>
jQuery(document).ready(function() {
var socket = io.connect();
var jsondata = "";
socket.on('server message', function(data){
console.log('got data from server',data)
jsondata = JSON.stringify(data);
//console.log('jsondata',jsondata)
$('.results').html(jsondata);
});
});
</script>
</body>
</html>
Please suggest what i am supposed to get route socket data in html page.
Thanks
Ok, let's try to understand why do you need to send data via the socket inside a route in the first place. Websockets are meant for sending data asynchronously without the client having to make a request. If the client is already making an HTTP request, then you can just send the data in the HTTP response.
Now having said there, there are clearly some use cases where you have to send data to some WebSocket channel based on the actions of some OTHER user's requests. If that is the case, there are multiple ways of doing this. One clean way would be to use an event-driven architecture.
Try something like this... find my comments inline below -
const express = require('express');
const router = express.Router();
const fs = require("fs");
const bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
// move the socket connection outside of the route controller
// you must register the event listeners before anything else
const connections = [];
io.sockets.on('connection', (socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
});
// Event emitter for sending and receving custom events
const EventEmitter = require('events').EventEmitter;
const myEmitter = new EventEmitter();
myEmitter.on('my-event', function (jsonobj) {
// do something here like broadcasting data to everyone
// or you can check the connection with some logic and
// only send to relevant user
connections.forEach(function(socket) {
socket.emit('server message', jsonobj);
});
});
router.get('/some-route', function (req, res, next) {
const jsonobj = [{ name: "john", score: 345 }, { name: "paul", score: 678 }]
// emit your custom event with custom data
myEmitter.emit('my-event', jsonobj);
// send the response to avoid connection timeout
res.send({ok: true});
});
module.exports = router;
At first glance, it looks like you are delcaring the URL prefix twice. Once in app.js and again in api.js.
Try localhost:port/api/api
If this is the case, change
router.get('/api', function(req, res, next){
to
router.get('/', function(req, res, next){
This will allow you to hit localhost:port/api and access your endpoint.
I am just starting to understand this myself, but I think where you are at is close.
In your app.js add to the end of the file:
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
const PORT = 3000;
server.listen(PORT);
console.log('Server is running');
var api = require('./routes/api');
//app.use('/api', api);
app.use('/api', (req, res) => {
res.sendFile(__dirname + '/api.html');
});
app.get('/', (req, res) => {
res.send("this is home location");
});
app.set("socketio", io); // <== this line
That stores the "io" variable in "socketio". Which you can grab in any of your other ".js" files.
var express = require('express');
var router = express.Router();
var fs = require("fs");
var bodyParser = require('body-parser');
const app = express();
const server = require('http').createServer(app);
//const io = require('socket.io').listen(server); // <== change this
const io = app.get("socketio"); // <== to this
console.log("inside api route");
router.get('/', function(req, res, next) {
console.log("api route called");
const connections = [];
var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
io.sockets.on('connection',(socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
socket.emit('server message', jsonobj);
});
//res.send(jsonobj)
});
module.exports = router;
And you should do that with any other variables which are required in other ".js" files.
Also note that in your files, you are setting the variables up again. It is better to do the same as I've shown you with "io". The only variable in other files I setup is "app" itself.
Hope this helps...
You tried to create and start the servers from two different places in your single project, which is inconvenient. You just need some cleanup, that's all.
app.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io').listen(server);
// Listen to sockets here instead of listening in routes/api.js
const connections = [];
var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
io.sockets.on('connection',(socket) => {
connections.push(socket);
console.log(' %s sockets is connected', connections.length); // this is not printing
socket.on('disconnect', () => {
connections.splice(connections.indexOf(socket), 1);
});
socket.emit('server message', jsonobj);
});
const PORT = 3000;
server.listen(PORT);
console.log('Server is running');
var api = require('./routes/api');
//app.use('/api', api);
app.use('/api', (req, res) => {
res.sendFile(__dirname + '/api.html');
});
app.get('/', (req, res) => {
res.send("this is home location");
});
routes/api.js
var express = require('express');
var router = express.Router();
var fs = require("fs");
var bodyParser = require('body-parser');
// Comment these out
// const app = express();
// const server = require('http').createServer(app);
// const io = require('socket.io').listen(server);
console.log("inside api route");
router.get('/', function(req, res, next) {
console.log("api route called");
// Comment these out
// const connections = [];
// var jsonobj = [{name:"john",score:345},{name:"paul",score:678}]
// io.sockets.on('connection',(socket) => {
// connections.push(socket);
// console.log(' %s sockets is connected', connections.length); // this is not printing
// socket.on('disconnect', () => {
// connections.splice(connections.indexOf(socket), 1);
// });
// socket.emit('server message', jsonobj);
// });
//res.send(jsonobj)
});
module.exports = router;
Leave your api.html as it is. Hope this helps.

i am trying to give an "hello world" in client side browser with express and http.?

here is my code app.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
app.use(express.static('Public'));
app.get("/send", function (request, response) {
response.sendFile('index.html', {root : './views'});
});
var listener = http.listen(process.env.HOSTNAME ||
'myhostname.com/nodejs/restapi' ,function(){
console.log('server running');
});
and my views/index.html
<script src="../client.js" type="text/javascript"> </script>
and my Public/client.js
$(function() {
$.get('/Nodejs/Restapi/send', function(send) {
console.log('hello world :o');
});
});
i dont know whats wrong its working perfectly in localhost

Node js, how to combine Socket.io with mustache

Socket.io can be used in the general html page, but it can not be used in the mustache page?
For example:
app.js
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'mustache'); // name your templates
app.engine('mustache', require('hogan-middleware').__express);
var routes = require('./routes/index');
app.use('/', routes);
routes\index.js
var express = require('express');
var router = express.Router();
var app = express();
var server = require('http').Server(app);
var io = require('socket.io').listen(server);
var request = require('request');
var serialport = require('serialport');
var Serialport = serialport;
router.get('/machine_mode', function(req, res, next) {
res.render('machine_mode', { title: 'test' });
});
io.sockets.on('connection',function(socket){
var str='hello';
io.sockets.emit('view',str);
});
views\test.mustache
<body>
</body>
<script src="/js/jquery-1.9.1.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
jQuery(function($){
var socket = io.connect();
socket.on('str',function(data){
})
});
the test page error:
can not GET
http://localhost:8001/socket.io/socket.io.js
app.js
var express = require('express');
var router = express.Router();
var app = express(); // Brackets Missing
var server = require('http').createServer(app); // Need to do like this
var io = require('socket.io').(server); // Need to pass server
var request = require('request');
var serialport = require('serialport');
var Serialport = serialport;
router.get('/machine_mode', function(req, res, next) {
res.render('machine_mode', { title: 'test' });
});
io.on('connection',function(socket){ // io.socket is not required
var str='hello';
sockets.emit('view',str);
});

separate logic from view with route

I'm pretty new to Node and I'm using express.
I'm trying to implement simple file explorer.
enough talking here's some code:
(root dir is /app for this ex.)
my app.js:
var express = require('express');
var fs = require('fs');
var path = require('path');
var ejs = require('ejs');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var explorer = require('./routes/explorer');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use("/public", express.static(__dirname + '/public'));
app.use('/', explorer);
server.listen(3000,function(){
console.log('Server started on http://localhost:3000');
});
io.on('connection',function(client){
console.log('connection with io established');
});
module.exports.app = app;
module.exports.server = server;
see that I have routing '/' to explorer
and the explorer.js:
var express = require('express');
var router = express.Router();
var fs = require('fs');
router.get('/', function(req, res, next) {
res.render('explorer',{
currentPath : currentPath
});
});
function getUserHome() {
var rawPath = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
return rawPath;
}
function clicked(){
console.log(getUserHome());
}
the view explorer.ejs:
<div class="clickable">clickme</div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:3000');
$('.clickable').click(function(){
socket.emit('clicked');
});
</script>
basically i want to catch the "clicked" emit from the view and trigger the clicked function in the explorer.js. in other words i want the view and the explorer.js talk by socket.io, so the view can talk with the file system.
i tried few way and got bunch of error.
thank you so much!
So you've triggered the event 'clicked' on your client side :
// Client side :
var socket = io.connect('http://localhost:3000');
$('.clickable').click(function(){
socket.emit('clicked');
});
Now, you have to catch it on the server side, in the explorer.js file :
// Server side :
// Instanciate your socket.io on the server side
var io = require('socket.io')(server)
// Listen for a client connection :
io.sockets.on('connection', function(socket){
// Inside the connection, you can now declare each function for each event triggered on the client side
socket.on('clicked', function() {
// This is your callback,
//+ the code in this scope will be executed
//+ only when the event 'clicked' is emitted
cliked();
});
});

Resources