socket.io Disconnect certain client - javascript

I am working with socket.io example for chat project. I want to add password protection to the chat application. This is just simple authentication. If user input wrong password, then server will disconnect this user.
Client side code:
var socket = io();
socket.emit('user name', username);
socket.emit('password', password);
Server side code:
socket.on('password', function (msg) {
if (msg !== '123321') {
io.emit('system info', 'Wrong password... Disconnecting ' + username+'...');
io.close(true);
return false;
}
});
The close() method doesn't work. the disconnected user still able to receive message from other users. So how to do this properly? Thank you.

Assuming you are creating an id (server side) with something like:
io.engine.generateId = (req) => {
return custom_id++; // custom id must be unique
}
You could close an specific connection using .disconnect() and you could call the id with socket.id
socket.on('password', function (msg) {
if (msg !== '123321') {
io.emit('system info', 'Wrong password... Disconnecting ' + username+'...');
io.sockets.connected[socket.id].disconnect();//<-- in this case it's just a number
}
});

Related

problem with Count number of online users with angular ,nodeJS and Socket.io

I have trouble to display the correct amount of online users. So When the user connect the count increase and decrease if disconnect but the problem is when i refresh the page the count still increasing i use angular as frontend and nodejs as backend please i need help to resolve this problem my code ServerSide is
var numberOfOnlineUsers = 0;
io.on('connection', function(socket) {
socket.on('join', function(data){
//joining
numberOfOnlineUsers++;
socket.emit('numberOfOnlineUsers',numberOfOnlineUsers); console.log('Hey, welcome! '+data.username);
socket.broadcast.emit('new user joined',numberOfOnlineUsers );console.log(numberOfOnlineUsers+ ' Users connected!');
});
socket.on('leave', function(data){
numberOfOnlineUsers--;
socket.broadcast.emit('user left',numberOfOnlineUsers);console.log(numberOfOnlineUsers+ ' Users connected!');
});
socket.on('demande',function(data){
socket.broadcast.emit('new demande', {demandeur:data.demandeur, demande:data.demande,datedem:data.datedem});
})
});
and Client Side is:
public ngOnInit(): void {
this.socket.on('new user joined', (numberOfOnlineUsers) => {
this.numberOfOnlineUsers = numberOfOnlineUsers;
console.log(this.numberOfOnlineUsers);
});
this.socket.on('user left', (numberOfOnlineUsers) => {
this.numberOfOnlineUsers = numberOfOnlineUsers;
console.log(this.numberOfOnlineUsers);
});
}
You should subscribe to socket.on('disconnect')
The logic on disconnect event at server side is fired when the socket disconnects due to any reason.
Check This Article Also
So the code should look like :-
io.on('connection', function(socket) {
.
.
.
socket.on('disconnect', (reason) => {
console.log('Socket disconnected');
});
});
My problem is when i reload the page the count of online users increment so i didn't have the real count of the users you understand the issue?

Concise example of how to join and leave rooms using Flask and Socket.io?

I'm trying to use socket.io with a Flask server connecting to JS.. I'm struggling with basically everything, but my first step is to make it so that users can connect to different channels. My broadcast message function is working, but when I click on a different channel, the messages do not get sent to a different channel.. What am I doing wrong?
JS:
document.addEventListener('DOMContentLoaded', ()=>{
// Send user back to login page if they didn't sign in
const username = localStorage.getItem('username');
if (username == null){
window.location = "/";
}
// Switch button active class when clicked
$('.list-group .list-group-item.list-group-item-action').click(function(e) {
$('.list-group .list-group-item.list-group-item-action.active').removeClass('active');
var $this = $(this);
if (!$this.hasClass('active')) {
$this.addClass('active');
}
e.preventDefault();
});
// Connect to socket.io
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
socket.on('connect', () => {
// Automatically connect to general channel
socket.emit('join',{"channel": "general", "username":username});
// When a channel is clicked, connect to that channel
document.querySelectorAll('.list-group-item').forEach(function(channel){
channel.onclick = () =>{
socket.emit('join',{"channel":channel.innerHTML, "username":username});
return false;
}
});
// When a message is sent, call 'send message' function from server
document.querySelector('#send-message').onsubmit = () => {
const message = document.querySelector('#m').value
socket.emit('send message', {'message': message});
// Clear message form
document.querySelector('#m').value = "";
return false;
};
});
// Callback from server for sending messages
socket.on('broadcast message', data =>{
console.log(data);
// Append message to list of messages
const li = document.createElement('li');
li.innerHTML = `${data.message}`;
document.querySelector('#messages').append(li);
});
});
Python Flask:
import os
from flask import Flask, render_template, url_for
from flask_socketio import SocketIO, emit, join_room, leave_room
from collections import defaultdict
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
socketio = SocketIO(app)
messages = defaultdict(list)
channels = ["Programming"]
#app.route("/")
def index():
return render_template("login.html")
#app.route("/chatroom/")
def chatroom():
return render_template("chatroom.html", channels=channels, messages=messages)
#socketio.on("send message")
def message(data):
print(data)
emit("broadcast message", {"message": message}, broadcast=True)
#socketio.on('join')
def on_join(data):
username = data['username']
channel = data['channel']
join_room(channel)
#send(username + ' has entered the room.', channel=channel)
if __name__ == '__main__':
socketio.run(app)
Think of a room as an array of users that stays on the server. When you send your message in "send message", you set broadcast=True, so it sends it as a global message to all users, as long as they are connected. If you only want to send to users in specific rooms, you will need to specify which room you want to send the message to from the client, each time you send a message, like this:
// client.js
socket.emit('join', { 'channel': channel, ... });
socket.emit('send message', {'message': message, 'channel': channel});
// server.py
#socketio.on("send message")
def message(data):
room = data['channel']
emit('broadcast message', data['message'], room=room)
I believe the first answer is correct. Just as a note, avoid using 'innerhtml' where possible especially in this case. By setting the innerhtml, anything a user writes in a message will be treated as html at the other end. This includes script tags which means someone could remotely run javascript on someone else's machine by sending a malicious message.
I would suggest using innerText or textContent. This will treat the message as plain text not html. They are slightly different so it may be worth looking into which one you need.
I would have done this as a comment but my rep isn't high enough.
tl:dr Use textContent or innerText instead of innerhtml.

socket.io rooms repeating same message per client

I'm using rooms to send a 'private' message to a client and it works however the message being sent is duplicated by the number of clients I have and I believe this is because of my .on('message') since this is still triggering for every client but only emitting to the correct client (but multiple times..)
server
io.sockets.on('connection', function(socket {
socket.on('join', function(data)
{
console.log('enter');
socket.join(data.user);
});
var rClient = redis.createClient();
rClient.subscribe('messagex');
rClient.on('message', function(channel, message) {
io.in(message.user).emit('messagex', {content: message.content});
});
socket.on('disconnect', function() {
rClient.quit();
});
});
receiver client
<script>
var username = prompt("test");
var socket = io.connect('http://localhost:8100');
socket.emit('join', {user: username});
socket.on('messagex', function(data) {
$('#messages').append('<p>' + data.content + '</p>');
});
So I have 3 clients (each with different users/rooms open) at the receiver page and I send a message from the sender to say user user1, then I will only receive the message on user1 client but it will receive 3 of the same message each time and the number of times duplicated seems to be the number of clients I have..
try this
subscribe.unsubscribe(channel);
when connection disconnect unsubscribe
io.sockets.on('connection', function(socket {
socket.on('join', function(data)
{
console.log('enter');
socket.join(data.user);
});
var rClient = redis.createClient();
rClient.subscribe('messagex');
rClient.on('message', function(channel, message) {
io.in(message.user).emit('messagex', {content: message.content});
});
socket.on('disconnect', function() {
rClient.unsubscribe('messagex');
rClient.quit();
});
});
I think you are using two channel at same time redis and socket.io, You have to make single channel i.e. socket.io only then there is no need make redis channel means no need to add pub/sub method when you transferring data through emit/on.

When namespacing I receive a "cannot GET error" displayed in browser

I'm using namespaces to differentiate between version of my socket.io chat app, and I'm having trouble with a "cannot GET error displayed in browser."
I plan on continually updating a chat app I made in a basic socket.io tutorial, and I want to be able to launch any version of it at any time. I'm going to do this by the use of namespaces. When I launch my app in browser at the location myserverlocation/v0.0.1 to access version 0.0.1 of my app, I get an error that states cannot GET '/v0.0.1'.
This is my server code:
var app = require('express')(),
server = require('http').Server(app),
io = require('socket.io').listen(server),
chat = io.of('/v0.0.1');
server.listen(80);
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
// usernames which are currently connected to the chat
var usernames = {};
chat.on('connection', function (socket) {
// when the client emits 'sendchat', this listens and executes
socket.on('sendchat', function (data) {
// we tell the client to execute 'updatechat' with 2 parameters
io.sockets.emit('updatechat', socket.username, data);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username) {
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
usernames[username] = username;
// echo to client they've connected
socket.emit('updatechat', 'SERVER', 'you have connected');
// echo globally (all clients) that a person has connected
socket.broadcast.emit('updatechat', 'SERVER', username + ' has connected');
// update the list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
});
// when the user disconnects.. perform this
socket.on('disconnect', function() {
// remove the username from global usernames list
delete usernames[socket.username];
// update list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
// echo globally that this client has left
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected');
});
});
And this is my client code:
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
var socket = io.connect('myserverlocation');
var chat = socket.of('/v0.0.1');
// on connection to server, ask for user's name with an anonymous callback
chat.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
chat.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
chat.on('updatechat', function(username, data) {
$('#conversation').append('<b>' + username + ':</b> ' + data + '<br>');
});
// listener, whenever the server emits 'updateusers', this updates the username list
chat.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('<div>' + key + '</div>');
});
});
// on load of page
$(function(){
// when the client clicks SEND
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
chat.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
</script>
<div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
<b>USERS</b>
<div id="users"></div>
</div>
<div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>
My chat app works fine without the use of namespaces, at myserverlocation/. I cannot figure out why I keep getting this error. After some investigation I think my usage of io.of() is incorrect, but I cannot seem to fix the problem. I'm not sure if my problem lies in the server code, the client code, or both.
Edit: After more investigation, I think my problem lies in the follow segment of code (though I could be mistaken):
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
Edit2: The problem did in fact lie in the code segment above. I should have been sending my whole /Chat directory as static content instead of using res.sendfile() to send one file. I will formally answer my own question when stackoverflow lets me (I have to wait 8 hours to answer my own question).
I managed to find what my problem was. The problem lied in the following section of code:
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
I was sending one particular file upon connection to my server, when I should be sending my entire /Chat directory as static content. This way, I can chose what version of my chat app I would like to launch. I managed to do this by changing a few lines of code in my server code:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(80);
// Chat directory
app.use(express.static('/home/david/Chat'));

How to reconnect anonymous user in XMPP/Jabber

I'm working on browser javascript xmpp client that connects anonymously to my server.
But when a user reloads the page or leaves it and subsequently returns to it I need
to reconnect to the server with the same anonymous account. How can I do this?
I'm using Strophe library (xmpp over bosh). So I already tried to do the following:
connection.connect(jid, "", onConnect);
this results in failure response from server:
<body xmlns='http://jabber.org/protocol/httpbind'>
<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<not-authorized/></failure>
</body>
and also:
connection.attach(jid, sid, rid, onConnect);
where jid, rid and sid are from cookies in both cases.
The second method is ok, but I can't manage with rid parameter correctly in all popular browsers.
Another approach is to use XEP-0077: "In-Band Registration" to create a brand new JID of the form [UUID]#yourhost on first login, with random password, then log back in to that account when you need to reconnect. Sweep through and delete the unused accounts periodically.
You can do it using jQuery (see $(document).ready). The example bellow uses Strophe for establishing BOSH communication to the XMPP server. The user joins the MUC room.
function onConnect(status) {
if (status == Strophe.Status.CONNECTED) {
var joined = false;
var participants = {};
$('#events').html('<text class="textmainleft">XMPP connection established. Ready to rock n roll!</text>');
connection.send($pres().c('priority').t('-1'));
connection.addHandler(notifyUser, null, 'message', 'groupchat', null, null);
connection.send(
$pres({
to: '[% groupchatroom %]#xmppserver.dom/' + "[% nickname %]"
}).c('x', {xmlns: 'http://jabber.org/protocol/muc'}));
} else if (status == Strophe.Status.AUTHFAIL) {
$(location).attr('href', AUTHFAIL_URL);
} else if (status == Strophe.Status.CONNFAIL) {
$(location).attr('href', AUTHFAIL_URL);
}
}
$(document).ready(function () {
var user_id = [% user_id %];
connection = new Strophe.Connection(BOSH_SERVICE);
connection.connect( "[% jid %]", "[% password %]", onConnect);
// Additional custom code goes here
});

Categories

Resources