I am listening to a small socket.io chat application. Every time a user joins, the server emits a message with the user's name and an id generated on the spot. However, when the user sends a message, the server only broadcasts the message with the userid, and without the username. This snippet of code shows the events that are triggered when a user connects and sends a message.
socket.on('chat_new_user', (data) => {
var json = JSON.parse(data);
console.log('new user!')
console.log(json.userid)
console.log(json.username)
});
socket.on('chat_new_message', (data) => {
var json = JSON.parse(data);
console.log(`${json.userid} - new message!`)
console.log(json.msg)
My issue is, how can I log the user's name to my console when he sends a new message, even though I only have the userID in the message json?
You may need to store the users data in an array
const users = []
socket.on('chat_new_user', (data) => {
var json = JSON.parse(data);
console.log('new user!')
console.log(json.userid)
console.log(json.username)
users.push({ id: json.userid, username: json.username })
});
socket.on('chat_new_message', (data) => {
var json = JSON.parse(data);
console.log(`${json.userid} - new message!`)
const user = users.find((user) => user.id === json.userid)
console.log(json.msg)
// check whether `user` exit
if (user) {
console.log(user.username)
}
Related
Is it possible to adapt a json from a live api according to the changes in the database?
server.js
const connection = mongoose.connection;
connection.once("open", () => {
//Live Stream - Posts
const observePosr_changes = connection.collection("posts").watch();
//Observe change in Data Base
observePosr_changes.on("change", (change) => {
//console.log('changes right now ->',change);
switch (change.operationType) {
//create request
case "insert":
//Create posts -> operationType function
break;
//patch/put request
case "update":
//Update posts -> operationType function
break;
//delete request
case "delete":
//Update posts -> operationType function
break;
}
});
});
I found using the documentation from mongodb a method by which I can detect live the changes in db atnci when post / patch / delete
controller/postController.js
//Create a new post - tahe all value and add into DB
exports.createPost = catchAsync(async(req,res)=>{
const create = await Post.create(req.body);
res.status(201).json({
status:"success",
data:create
});
});
//Get Information from DB
exports.getAllPosts = catchAsync(async(req,res,next)=>{
const getAll = await Post.find()
res.status(200).json({
status:"success",
data:{
post:getAll
}
});
});
Is there a possibility to use the socket in this situation to make the application live.
That is, at the moment the mobile application and the website to see the newly added content must refresh.
you want to configure the server first
io = socket(server); -- server : express or any other
io.on("connection", function (socket) {
//console.log("Made socket connection");
});
so you can connect the socket from your client app using unqiue event name
this.socket = io.connect(YOUR_URL);
this.socket.on(HERE_YOUR_EVENT_NAME, (data: any) => {
-- your get the data here
});
when ever you want to send the data to client app emit the data using event name in server side using below code
io.emit(event_name, data);
I have recently started learning about Node js and developed a Realtime chat application where whoever is connected to the server they can have a chat but now I want to add a feature of private chat between two users only so how can I achieve it? I have read about the room functionality of socket.io but by that I can get that it's a room and in that room there can be many users and they can have chat but it's not personal means many users can join the same chat. I need to know how to implement chat feature where two people can have a chat no third person can enter that particular chat. My question is different than other questions present here as I want to implement both the functionalities I need group and private chat both in one application.
My idea is in my group chat functionality username and message are displayed so if one user clicks on username then the person can start their personal private chat no third person can join it.
Here I am sharing my code snippets for your reference
Server.js
const io = require('socket.io')(http)
io.on('connection', (socket) => {
console.log('Connected...')
socket.on('message', (msg) => {
socket.broadcast.emit('message', msg)
})
})
Client.js
const socket = io()
let name;
let textarea = document.querySelector('#textarea')
let messageArea = document.querySelector('.message__area')
do {
name = prompt('Please enter your name: ')
} while(!name)
textarea.addEventListener('keyup', (e) => {
if(e.key === 'Enter') {
sendMessage(e.target.value)
}
})
function sendMessage(message) {
let msg = {
user: name,
message: message.trim()
}
// Append
appendMessage(msg, 'outgoing')
textarea.value = ''
scrollToBottom()
// Send to server
socket.emit('message', msg)
}
function appendMessage(msg, type) {
let mainDiv = document.createElement('div')
let className = type
mainDiv.classList.add(className, 'message')
let markup = `
<h4>${msg.user}</h4>
<p>${msg.message}</p>
`
mainDiv.innerHTML = markup
messageArea.appendChild(mainDiv)
}
// Recieve messages
socket.on('message', (msg) => {
appendMessage(msg, 'incoming')
scrollToBottom()
})
function scrollToBottom() {
messageArea.scrollTop = messageArea.scrollHeight
}
Please help me out!
when a new user join keep that socket id, and while sending message send that unique userid and emit message to that socket only,
const io = require('socket.io')(http)
var user={};
io.on('connection', (socket) => {
console.log('Connected...')
socket.on('join', (userid) => {
users[userid]=socket.id;
});
socket.on('privateMessage', (data) => {
io.sockets.socket(users[data.to]).emit('message', data.msg);
});
socket.on('publicMessage', (msg) => {
socket.broadcast.emit('message', msg)
});
});
I am trying to build an chat apps using socket.io and node.js for backend and flutter for frontend... so far I have been trying to send message to all connected user, is there a way to send message to specific user? here is part of my backend code
io.on('connection', (socket) => {
console.log(`id: ${socket.id}`)
socket.on('send_message', (msg) => {
var detail = JSON.parse(msg)
socket.in(detail["receiver"]).emit('to_user', msg)
})
});
in flutter I am using socket_io_client package (https://pub.flutter-io.cn/packages/socket_io_client) but I don't know how to emit message for specific user
here is part of code for frontend
StreamController<String> _data = StreamController<String>();
socket.on('send_message', (x) {
_data.sink.add(x);
});
sendChat(String msg, String sender, String receiver) {
Map map = {"msg": msg, "snd": sender, "rcv": receiver};
var mapbody = json.encode(map);
socket.emit('send_message', mapbody);
}
Stream<String> get sendChat => _data.stream;
you have to have the socket.id and use io.sockets.socket(SocketId).emit(msg) to send message
var express = require("express");
var redis = require("redis");
var sio = require("socket.io");
var client = redis.createClient()
var app = express.createServer();
var io = sio.listen(app);
io.set("store", new sio.RedisStore);
// In this example we have one master client socket
// that receives messages from others.
io.sockets.on('connection', function(socket) {
// Promote this socket as master
socket.on("I'm the master", function() {
// Save the socket id to Redis so that all processes can access it.
client.set("mastersocket", socket.id, function(err) {
if (err) throw err;
console.log("Master socket is now" + socket.id);
});
});
socket.on("message to master", function(msg) {
// Fetch the socket id from Redis
client.get("mastersocket", function(err, socketId) {
if (err) throw err;
io.sockets.socket(socketId).emit(msg);
});
});
});
some options you have here.
first :
you can store your connected clients ids to redis .
use io-redis :
and store your client id in it:
for storing ids in redis:
await redisClient.lpush(`socket_members`, socket.id);
for getting the specefic id:
let client = await redisClient.lrange(
`socket_members`,
0,
socket.id
);
the second option is you can create an authentication middleware
const jwt = async(socket, next) => {
let token = socket.handshake.query.token
let verify = jwt.verify(socket.handshake.query.token, jwt_encryption, async(err, decoded) => {
// find user with decoded token
if (!user) {
return next(new Error(JSON.stringify({ status: 401, message: 'unuthorized' })));
}
socket.user = user._doc
return next()
})
};
and use it in socket io instance :
io.use(jwt);
the authenticated user is in socket.user.
hope this would help
I would like to integrate Socketio django redis and nodejs. My problem is that i dont know how to make a room specific to two logged in users.
Say, For example user A is logged in and user B logs in after 20 minutes, User B should automatically join the room with user A when he clicks on user A's chat.
You should save your rooms name on database then, and when user B logged in or click the rooms he/she will be joined with that room name. I prefer using using random generated string for room name.
io.on('connection', (socket) => {
socket.on('join room', (data) => )
const userA = data.userB;
const userB = data.userA;
const roomname = data.roomName;
// I use mongodb
const socketRoomName = MyRoomModel.findOne({ roomname })
.then(response => response)
socket.join(socketRoomName)
// send message after user connected to rooms
socket.to(socketRoomName).emit('online', data.message)
})
But if you did not want to use rooms and namespace on socket.io you can handle logged in and mapping them on connection
const sessionsMap = {};
io.on('connection', (socket) => {
// ask user id on client can be email, must unique
socket.emit('askForUserId');
socket.on('userIdReceived', (userId) => {
// map userid to sessions map
sessionsMap[userId] = socket.id;
});
socket.on('send', (message) => {
const receiverId = sessionsMap[message.receiverId];
const messageData = message.data;
// this will send only on user with that specific user id
socket.broadcast.to(receiverId).emit('my message', messageData);
});
});
I am trying to build a live chat, I am using mongodb and socket.io to store the messages and users.
When a new user is created that user is stored in the mongodb and in the socket object.
If a user refreshes the page the user is removed from the socket object, meaning now in order for that person to get back in they have to create a new username and that generates a new socket.
Here is what my server side code looks like
/*
|--------------------------------------------------------------------------
| Live socket communication with front end:
|--------------------------------------------------------------------------
|
|
*/
var users = {};
io.sockets.on('connection', function (socket) {
// Listen to a new user then emit the user to all clients
socket.on('new user', function (data) {
// Check mongodb to see if the user exists and emit proper message
models.Message.findOne({username:data},function(err,user){
if(err){
console.log('something went wrong')
}
else if(user){
socket.emit('username taken', 'something');
}
else{
socket.emit('create user', data);
socket.userName = data;
socket.connected = true;
users[socket.userName] = socket;
io.sockets.emit('user name', Object.keys(users));
}
});
});
socket.on('facebook id', function(data) {
models.User.findOne({username:data.name}, function(err, user) {
if (user) {
console.log('User already exists');
socket.userName = data.name;
socket.facebook_id = data.id;
socket.connected = true;
users[socket.userName] = socket;
io.sockets.emit('user name', Object.keys(users));
}
else {
var newUser = new models.User({
username: data.name,
facebook_id: data.id
});
newUser.save(function(err, user) {
console.log('successfully inserted user/user: ' + user._id);
});
}
});
});
// Listen to a new message then emit the message to all clients
socket.on('send message', function (data, callback) {
io.sockets.emit('new message', {message: data, username: socket.userName, facebook_id: socket.facebook_id});
});
// Logic when client disconnects
socket.on('disconnect', function (data) {
if(!socket.userName) return;
seeder.disconnect(socket.userName);
delete users[socket.userName]
io.sockets.emit('user disconnected', Object.keys(users));
});
});
You see in my disconnect I remove the socket from the users object.
My question would be is there a way to save the socket info on disconnect then if the same socket tries to connect have it recognize the user and continue?
Additonal: I am thinking maybe I need to focus on creating a user login with mongodb first, then using that log in session data and pass that to the socket, creating a socket object with current database details? Does that sound like something that makes more sense, is that possible?
You can use cookies to identify users. Generate a random hash, put it in cookies, and thus this data will be transferred when establishing connection between client and server.
The client code may look like:
function generateHash(len) {
var symbols = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
var hash = '';
for (var i = 0; i < len; i++) {
var symIndex = Math.floor(Math.random() * symbols.length);
hash += symbols.charAt(symIndex);
}
return hash;
}
if (!/\buser_id=/.test(document.cookie)) { //if no 'user_id' in cookies
document.cookie = 'user_id=' + generateHash(32); //add cookie 'user_id'
}
//here goes establishing connection to server via `io.connect`
On the server-side you can write:
io.sockets.on('connection', function (socket) {
var cookie = socket.handshake.headers.cookie;
var match = cookie.match(/\buser_id=([a-zA-Z0-9]{32})/); //parse cookie header
var userId = match ? match[1] : null;
//...
Thus you have userId variable which is unique for each user. Then you can comment this line:
delete users[socket.userName]
because you should keep the user data.
You may now store your users object with userId (not username) as a key, and on each connection check whether users[userId] != null. And if such user exists, use their socket info