0

have been trying to create a chat app with node.js and socket.io, but have been stuck for a while and heres why, i succeeded in implementing sending of private messages between connected users by clicking on the username of the person u want to chat privately with, but the problem i now face is that, for example let say there are 3 connected users in the chat app(say joy, grace,shanel) when joy decides to chat with grace, the chat app handles this quite well,but if joy decides to chat with shanel after first chatting with grace, joy's private messages that are meant for shanel ends up being sent to grace, (i.e both grace and shanel recieves this private message for grace), this is the problem have been facing. my codes are below, sorry for the essay, i want anyone trying to help understand my situation :)

server.js code

   var express = require('express');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var usernames={};
var sockets = {};
var names= {};


app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  socket.on('send_msg', function(msg){
     console.log('a user connected');
    io.emit('chat message', msg);
    //console.log(msg);

  });

   socket.on('new_user',function(user){
    console.log('new user:'+user);
       names[socket.id] = user;
       socket.nickname= user;
       usernames[socket.nickname] = socket;
        sockets[user]=socket.id;
        socket.emit('update_personal', "you are now online");
        io.emit('update_users',names);

    });

    socket.on('disconnect', function(){
        io.emit('update_personal', usernames[socket.id]+' is now offline');
        //delete usernames[socket.id];
        delete names[socket.id];
         delete usernames[socket.nickname];
         // io.emit('update_users',usernames,usernames[socket.id]);
            io.emit('update_users',names);
          //console.log(usernames+'specific user id'+usernames[user]);
    });

    socket.on('private_msg', function(msg,recipient,sender){

        console.log('you are trying to send '+msg+' to '+recipient+ ' from '+sender);


        var id = sockets[recipient];

        console.log(sockets[recipient]);
      io.to(id).emit('received_p_msg', msg,sender,recipient);

      recipient = '';
      console.log('value in recipient:'+recipient);


    });
});

http.listen(3000, function(){
  console.log('listening on *:3000');

});

client.html

<!doctype html>
<html>
  <head>

    <title>my chat app</title>
    <!------------------
    <style>
    <!-----------
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
      #chat_msg{

      }
    </style><!-------!>

  </head>
  <body>
  <!---username login here----->
  <div id="login">
  <form id="chat_msg">
  <label>Enter Username:</label>
  <input type="text" id="username"/>
  <input type="button" id="join" value="Create Username"/>
  </form>

  </div>
  <div>
  <div id="online_users"><li>List of online users:</li></div>
  </div>

  <!---public room chat begins here----->
  <div id="chat" style="display: none;">

    <ul id="messages"></ul>
    <form action="">
      <input id="msg" autocomplete="off" />
      <button id="send" >Send</button>
    </form>
    </div>

    <!---private chat begins here----->
    <div id="private_chat" style="display: none;">
    <p id="private_user">Private chat with: </p>
    <div id="private_msg"></div>

    <form action="">

      <input id="p_msg" autocomplete="off" />
      <button id="p_send" >Send private msg</button>
    </form>
    </div>
    <script src="/socket.io/socket.io.js"></script>
     <script src="jquery-2.1.0.js"></script>
    <script>
    $(document).ready(function(){

      var socket = io('http://192.168.173.1:3000/');

      $('#chat').hide();
       $('#username').focus();


      $('form').submit(function(e){
        e.preventDefault();
        });

        var username = $('#username').val();


        $('#join').click(function(){
           var username = $('#username').val();
           console.log('entered username '+username);
           if(username !=''){
            socket.emit('new_user', username);
            $('#login').detach();
            $('#chat').show();
            $('#msg').focus();
           }
        });

        $('#send').click(function(){
             socket.emit('send_msg', $('#msg').val());
        $('#msg').val('');

        });


      socket.on('chat message', function(msg){
        $('#messages').append($('<li>').text(msg));
      });

      socket.on('update_personal', function(status){
        $('#messages').append($('<li>').text(status));
      });

      socket.on('update_users', function(names){
        console.log(names);


        if(true) {

                              $("#online_users").empty();
                $.each(names, function(clientid, name) {
                    $('#online_users').append("<li><a href='#' id='"+name+"' name='"+name+"' class='private'> " + name + "</a></li>");
                });
                   // $('#online_users').html("<li><a href='#' id='"+name+"' name='"+name+"' class='private'> " + name + "</a></li><br/>");


         $('a.private').click(function(){
      $('#private_chat').hide();

      $('#private_chat').show();
      var sender = username;


    var recipient = $(this).attr('name');


      console.log('name gotten is:'+recipient);
      $('p#private_user').html('private chat with :'+ recipient);

        $('#p_send').click(function(){
            msg = $('#p_msg').val();
            if(msg!=''){
                recipient=recipient;
             socket.emit('private_msg', msg,recipient,sender); // msg from sender, username of the sender, username of recipient
       $('#p_msg').val('');
       }else{$('#p_msg').val('please enter a valid msg');}
        });
      });

                    }
      });
      socket.on('received_p_msg', function(msg,sender,recipient){
         $('#private_chat').show();

         console.log('received privatemsg: '+msg);
         $('#private_user').html('privatE chat with : '+ sender);
        $('#private_msg').append($('<div>').html(msg+'</div>'));

        //to continue chat after receiving initial private msg
        $('#p_send').click(function(){
            msg = $('#p_msg').val();
               if(msg!=''){
             socket.emit('private_msg', msg,sender,recipient); // msg from sender, username of the sender, username of recipient
        $('#p_msg').val('');
       }else{$('#p_msg').val('please enter a valid msg');}

        $('#p_msg').val('');

        });

       });

      socket.on("disconnect", function(){
            $("#msgs").append("The server is not available");

      });



      });
    </script>
  </body>
</html>
jamie_1
  • 28
  • 7
  • Check rooms and namespaces in the socket.io documentation, that should solve your issue – matteospampani Sep 02 '14 at 20:10
  • thanks for your reply, but i feel your reply was a bit vague as am still kinda new to socket.io and node, i would really appreciate it, if you could explain a bit, thanks a lot!:) – jamie_1 Sep 03 '14 at 09:18
  • Sorry but at the moment I can't, I'll explain it better later. Here is the [source code](https://github.com/Automattic/socket.io/tree/master/examples/chat) of the [online demo](http://socket.io/demos/chat/). Hope it helps – matteospampani Sep 03 '14 at 09:31
  • alright, i appreciate your help, i ll check those links out, thanks – jamie_1 Sep 03 '14 at 09:43
  • i checked the links, they were more on about public chats, am concerned about the problem i faced with my private chats(explained above).i ll be patient till you are free to explain better on how to solve this private chat issue of mine, till then, thanks again. – jamie_1 Sep 03 '14 at 09:49

2 Answers2

0

Regarding your issue I noticed that if you want to open multiple private chats you can't because there is only one username and so it isn't possible to choose more than one client to send the chat message to. You need to extend the username variable into an array of usernames for example.

I found a possible bug in your client.html file, in which username was taken from $("#username").val() but it was undefined. I suggest you this fix if I understood correctly your code (3 different lines):

// the line below differs
var username = null;
var socket = io('http://192.168.173.1:3000/');

$('#chat').hide();
$('#username').focus();

$('form').submit(function(e){
    e.preventDefault();
});

// the line below differs
//var username = $('#username').val();

$('#join').click(function{
    // the line below differs
    username = $('#username').val();
    console.log('entered username '+username);
    if(username !=''){
        socket.emit('new_user', username);
        $('#login').detach();
        $('#chat').show();
        $('#msg').focus();
   }
});
matteospampani
  • 576
  • 4
  • 12
  • thanks for the quick response, i fixed the error u pointed out on the client side, the former code was working anyway cos i redeclared the username variable again(poor coding ethics). concerning the private chat issues, if you look at the code i sent above from the "update_users" event after comparing it with the server side code i sent, u ll observe that the list of available usernames to chat with isnt one, its an object that contains connected usernames and the socket.id, which is what i sent to the server side. please check again, thanks for your help – jamie_1 Sep 03 '14 at 21:00
  • thanks a lot bro! ur a saver, after u pointed out that bug u found, i decided to take another look at my code, i found 3 others just like the one u discovered, apparently, the recipient variable which was not global was being redeclared at every point, my chat app now works!, i really do appreciate your help – jamie_1 Sep 04 '14 at 00:14
  • @matteospampani hi, hope you are doing good, i have a very similar question if you can please have a look at. https://stackoverflow.com/questions/65277256/react-native-one-to-one-conversation-using-socket-io – kd12345 Dec 15 '20 at 06:37
  • @kd12345 Yes, it is similar problem, but this comment was made 4 years ago, now everything is changed in the sockets and I cannot help you, sorry... :-( – matteospampani Dec 15 '20 at 13:46
  • @matteospampani, thank you for getting back to me. Has it become more difficult to implement sockets ? Do you suggest i still use sockets or is there a better alternative? – kd12345 Dec 15 '20 at 13:49
  • I think sockets are fine, but this question is "4 years old" and in software it is a huge amount of time! So implementation could be very very different now (and I am no more up to date to address you in the issue you posted) – matteospampani Dec 17 '20 at 08:12
  • @matteospampani is possible to explain the concept of sockets, because i am very confused at the moment. i tried very link available online but i keep getting confused more and more.https://stackoverflow.com/questions/65377025/react-native-nodejs-socket-io – kd12345 Dec 20 '20 at 06:22
0

Since you want the messages of two parties to remain private between them, I suggest that you create a room for each of the two parties. As it stands now it think you're sending / broadcasting your event to all parties in the room which contains all the users.

Norbert
  • 5,474
  • 14
  • 35
  • 60