I got a middlware to validate my socket by jwt
but I have a problem making new events in other folders
Not to get everything in my app.js
I did this to authenticate my socket:
let io = require('socket.io')(server);
app.set("io", io);
io.use(verify.passportJwtAuth);
io.on('connection', function(socket) {
console.log('Authentication passed!');
// now you can access user info through socket.request.user
// socket.request.user.logged_in will be set to true if the user was authenticated
socket.emit('success', {
message: 'success logged in!'
});
});
midd:
async passportJwtAuth(socket,next) {
const secret = config.jwt.secret;
const token = socket.handshake.query.token;
jwt.verify(token, secret, function(err, decoded) {
if(err) {
return next(err);
}
console.log("sucess");
return next();
});
}
I've tried to make a new event:
const socketRouter = require('./routes/socket');
io.use(verify.passportJwtAuth);
io.on('connection', function(socket) {
console.log('Authentication passed!');
// now you can access user info through socket.request.user
// socket.request.user.logged_in will be set to true if the user was authenticated
socket.emit('success', {
message: 'success logged in!'
});
});
socketRouter.configuration();
my socketRouter.configuration:
const socketController = require ('../controllers/SocketController');
const verify = require('../auth/index');
const socket = require('socket.io');
module.exports = {
configuration: () => {
socket.on ('message', (message) => {
socket.emit ('myevent', {message: 'Ok, You are signed in'});
console.log (message);
console.log (`Socket $ {socket.id}`)
});
}
}
error:
C:\Users\SpiriT\Documents\Projetos\FtcJokenPo\back\src\routes\socket.js:6
socket.on ('message', (message) => {
^
TypeError: socket.on is not a function
at Object.configuration (C:\Users\SpiriT\Documents\Projetos\FtcJokenPo\back\src\routes\socket.js:6:14)
at Object.<anonymous> (C:\Users\SpiriT\Documents\Projetos\FtcJokenPo\back\src\app.js:36:14)
I didn't want to have to leave all my socket logic in my app.js
Also this way soon when I turn on the server I already call this module (I wanted it to call only when I use socket.on on the front end
Could someone give me a hand?
my front end:
verify = () => {
let socket = null;
var token = 312312312;
socket = io('http://localhost:8080', {
query: {token: token}
});
socket.on('error', function(err) {
console.error(err);
});
// Connection succeeded
socket.on('success', function(data) {
console.log(data.message);
})
}
In your socketRouter.configuration file, with this code below, your socket variable is not what you need it to be. It looks like you want it to be a specific connected socket that you can listen for incoming messages on. You are trying to use:
const socket = require('socket.io');
to get that socket, but that's simply the export object from the socket.io module and has nothing to do with an existing connected socket.
What it appears you need to do is to pass a particular socket to your configuration function and then use that argument in your function. First change the configuration module to this:
const socketController = require ('../controllers/SocketController');
const verify = require('../auth/index');
module.exports = {
configuration: (socket) => {
socket.on ('message', (message) => {
socket.emit ('myevent', {message: 'Ok, You are signed in'});
console.log (message);
console.log (`Socket $ {socket.id}`)
});
}
}
This removes the require('socket.io') line and adds a socket argument to the configuration function.
Then, where that configuration() function is called, you need to pass that socket argument:
const socketRouter = require('./routes/socket');
io.use(verify.passportJwtAuth);
io.on('connection', function(socket) {
console.log('Authentication passed!');
// now you can access user info through socket.request.user
// socket.request.user.logged_in will be set to true if the user was authenticated
socket.emit('success', {
message: 'success logged in!'
});
// let the socketRouter add any message handlers it wants to for this socket
socketRouter.configuration(socket);
});
Related
I am trying to setup Socket IO to work well in different controllers in my Express application.
Here is how I have Socket IO initialized in my server.js
//Run When Connection Received
io.on('connection', (socket) => {
socket.emit('message', 'This is a test message from the server.')
})
Here is what one of my controllers looks like:
const getComments = asyncHandler(async (request, response) => {
const { liveID, token: accessToken } = request.body
var source = new EventSource(
`https://streaming-graph.facebook.com/${liveID}/live_comments?access_token=${accessToken}&comment_rate=one_per_two_seconds&fields=from{name,id},message`
)
source.onmessage = function (event) {
// Do something with event.message for example
console.log(event)
// THIS IS WHERE I NEED TO EMIT A SOCKET IO EVENT.
// THE DATA IN 'event' NEEDS TO BE SENT BACK TO THE CLIENT VIA THE SOCKET
}
source.onerror = function (error) {
console.log('Error!')
console.log(error)
}
source.onopen = function (event) {
console.log(event)
}
})
I have been trying to follow this documentation from Socket IO but for the life in me I can not seem to figure out how to make this work with my above example I have tried so many different things and I just seem to be missing something.
https://socket.io/docs/v4/server-application-structure/
Any help here would be greatly appreciated!
What you can do to have access to io in controller is to attach it to request object like so:
app.use((req, res, next) => {
req.io = io;
next();
});
When a socket connects add an user id to the socket
io.on('connection', (socket) => {
// assuming you send user id in a header for example
socket.userId = socket.client.request.headers.userId;
})
Then in a controller:
const getComments = asyncHandler(async (request, response) => {
var io = request.io;
// https://socket.io/docs/v4/server-api/#serverfetchsockets
// return all Socket instances
const sockets = await io.fetchSockets();
// assuming there's a loggedin user object attached to request
const socket = sockets.find(s => s.userId === request.user.id);
const { liveID, token: accessToken } = request.body
var source = new EventSource(
`https://streaming-graph.facebook.com/${liveID}/live_comments?access_token=${accessToken}&comment_rate=one_per_two_seconds&fields=from{name,id},message`
)
source.onmessage = function (event) {
// Do something with event.message for example
console.log(event)
socket.emit(....);
}
source.onerror = function (error) {
console.log('Error!')
console.log(error)
}
source.onopen = function (event) {
console.log(event)
}
})
Hey super new to socket io and web sockets in general. I have a chatting app scenario with socket io where client emits to the server and the server emits back to the client.
In my case the emits from the client side are picked up on the server side so far no problems.
However on the client side there are some socket.on statements there to pick up stuff from the server. A generic console.log after connection fires, but the other socket.on statements do not.
My thought was that maybe the server side emits aren't firing. Where it gets weird though is that when I change something in the client side file with the socket.on statements, the client side statements will pick up the emits from the server until the next time I refresh the page.
It is also work noting that these client on statements work with the info that was gathered before the save: if something is like
Client-side:
socket.on("message", (data) => {
console.log(foo)
});
and I change it to
socket.on("message", (data) => {
console.log(bar)
});
and then trigger the chain of emits,
the socket.on("message... will fire properly but it will log "foo". My guess is that saving the client side socket file is creating a new connection or something, but I'm curious as to why only the old connection is picking up things from the server and not the new one?
My code for reference:
(client)
const token = localStorage.getItem("messenger-token");
const socket = io.connect('http://localhost:3001', {
query: {token}
});
//const socket = io('http://localhost:3001');
socket.on("connect", () => {
console.log("connected to server");
socket.on("new-message", (data) => {
console.log(data.message)
store.dispatch(setNewMessage(data.message, data.sender));
});
socket.on("mark-as-read", (data) => {
store.dispatch(markedAsRead(data.convoToUpdate,'socket'));
});
});
(server)
//www
const server = http.createServer(app);
app.io.attach(server,{'pingInterval': 2000, 'pingTimeout': 50000});
//app
app.io = require('socket.io')();
require('./sockets')(app)
app.io.use(function(socket, next){
const token = socket.handshake.query.token
if (token) {
jwt.verify(token, process.env.SESSION_SECRET, (err, decoded) => {
if (err) {
return next(new Error('Authentication error'));
}
User.findOne({
where: { id: decoded.id },
}).then((user) => {
return next();
});
});
} else {
return next();
}
})
//sockets module
module.exports = (app) => {
app.io.on("connection", (socket) => {
console.log("connected")
socket.on("new-message", (data) => {
socket.broadcast.emit("new-message", {
message: data.message,
sender: data.sender,
});
socket.on("mark-as-read", (data) => {
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
});
I don't know if this is appropriate but it turns out I didn't have a problem.
the server logic:
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
uses broadcast.emit instead of regular emit. This sends the new info to everyone except the sender as seen in the docs. oops
I have a Vue app that sets up a socket connection when the user logs in.
My component has a method that accesses an outer variable socket I made so that I can emit events in other methods..
onLoginSuccess() {
socket = io(`${process.env.SERVER_URL}`);
socket.emit('login', localStorage.getItem('username'));
socket.on('login-response', (response) => {
if (!response.status) {
alert(response.message);
return false;
} else {
this.$router.push("/home");
this.$refs.form.reset();
}
});
}
However, when I try to do socket.emit in another event it doesn't work:
onSocketLogout() {
console.log('socket logout call', socket)
socket.emit('delete_username_from_array', localStorage.getItem('username') );
},
Socket doesn't seem to be null/undefined on the console and I tried putting the same event emitter on the onLoginSuccess function and it works fine. It just doesn't work when I use socket in other functions or places outside the initial connection.
Here's my socket io server code:
let logged_in_users = [];
const io = require('socket.io')(http);
io.on('connection', function(socket){
console.log(`Socket ${socket.id} connected`);
socket.on('login', function(username){
// check duplicates
if(logged_in_users.includes(username)){
socket.emit('login-response', {
message: 'It seems that you have already logged in on another browser. Please logout first.',
status: false
});
return false;
}else{
socket.emit('login-response', {status: true});
console.log(`${username} logged in`)
logged_in_users.push({ username, id: socket.id });
}
});
// for logout
socket.on('delete_username_from_array', function(username){
console.log('removing username from array')
// delete the username from the array of logged in users
logged_in_users.splice( logged_in_users.indexOf(username), 1 );
});
socket.on('test', () => {
console.log("TEST")
})
socket.on('disconnect', () => {
console.log(`Socket ${socket.id} disconnected`);
console.log(logged_in_users)
})
});
I'm having problem finding the right answer for my problem. I want to had private messaging for every user like Telegram if I may say. Or like notifications on StackOverflow the socket event are only send to specific user.
io.on('connection', function (socket) {
// this will be only sent to a user that just connected
socket.emit('news', { hello: 'world' });
});
But how to send specific message with custom id?
Here my socket.js
const socketio = require('socket.io')
const { redis, saveUser } = require('./redis')
module.exports.listen = function(app){
io = socketio.listen(app)
io.on('connection', socket => {
console.log('connected user', socket.id)
socket.on('join', (payload) => {
redis.get(payload.email (err, socket_id) => {
socket.broadcast.to(socket_id).emit('join', `Hello ${payload.whoChat.name} Chat you`)
})
})
})
return io
}
but this doesn't send anything to my user, if using rooms it will send directly to the rooms and when i look for docs io.to() and io.broadcast.to() can be use with sockets rooms.
so i decided to take it simple but wrong here my server.js rigth now.
io.on('connection', function (socket) {
socket.on('join', payload => {
socket.emit('join', payload)
})
and on client-side
socket.on('join', (payload) => {
// Compare data from socket with local data if match then push the message
// to users who recieve
if ( payload.userId === localData.userId ) {
this.message.push(payload.message)
}
})
but with that actually I send it to all users... how to do it properly and right? and how to save the users socket.id? since socket.id are generated randomly how do you save it for the future request when user disconnect?
You need to maintain a map of _socket_id/user_id_
Server
const sessionsMap = {};
io.on('connection', (socket) => {
socket.emit('askForUserId');
socket.on('userIdReceived', (userId) => {
sessionsMap[userId] = socket.id;
});
socket.on('send', (message) => {
const receiverId = sessionsMap[message.receiverId];
const messageData = message.data;
socket.broadcast.to(receiverId).emit('my message', messageData);
});
});
Client
const userId = 'FOO';
io.on('askForUserId', () => {
io.emit(userId);
});
io.on('send', (message) => {
console.log('You received a message');
console.log(message.data);
});
Note
Make sure to check out the Socket.IO cheatsheet it covers a lot of commands and use cases.
I'm new in node js and socket io, I'm trying to create interactive quizzes based on pin code given in the url for ex: http://domain/start/5555 should create a quiz page with name 5555 and when clients have the pin code they can connect to this quiz. So it means i have to have a quiz page which shows all connected clients for example but i have some prblems with io.sockets.in(pincode).emit()
because i don't know if i'm creating rooms correctly or not!
here is my code
Client.js
var socket = io();
socket.on('connect', function () {
var params = jQuery.deparam(window.location.search);// To get the name and the room
socket.emit('join', params, function (err) {
if (err) {
alert(err);
window.location.href = '/join.html';
} else {
console.log('No error');
}
});
});
Server.js
app.get('/start/:pincode', (req, res) => {
io.on('connection', (socket) => { // to rigester connection listener
console.log('New user is connected');
// When somebody connects it verifies if the name and the room are valid strings
socket.on('join', (params, callback) => {
if (!isRealSrting(params.name) || !isRealSrting(params.pincode)) {
return callback('Name and pincode are required');
}
socket.join(params.pincode);
users.removeUser(socket.id);//Remove the user from other places
users.addUser(socket.id, params.name, params.pincode);
var x = users.getUserList(params.pincode);
console.log(x);
io.sockets.in(params.pincode).emit('updateUserList', { //here it doesn't work i don't know why!
users: users.getUserList(params.pincode),
pincode: params.pincode
});
socket.emit('newMessage', {
user: params.name,
pincode: params.pincode,
readyMessage: 'You are connected'
});// when the user connect to the server he gets this message
callback();
});
socket.on('disconnect', () => {
var user = users.removeUser(socket.id);
if (user) {
io.emit('updateUserList', users.getUserList(user.pincode));
//io.to(user.room).emit('newMessage', generateMessage('Admin', `${user.name} has left`));
}
});
});
res.render('start.hbs', {
pincode: req.params.pincode
});
});
and the main page
Start.js
var socket = io();
var pincode;
socket.on('updateUserList', function (users) {
console.log('here');
var ol = jQuery('<ol></ol>');
var usercount = users.users.length; // Players number
pincode = users.pincode;
});
Any help or suggestion please?