I've been playing around a bit with NodeJS and recently socket.IO, I come from PHP development and try to understand really how to work with Node and socket.IO
I started building a chat app and when I were to test it on different devices I noticed that when I for instance log in to another account through my phone, the browser window updates and gets the same user as I logged into on my phone
index.html
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</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: 0.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; }
</style>
</head>
<body>
<div id="chatLogin">
<input type="text" name="password" id="username" placeholder="Username..." /><br>
<input type="password" name="password" id="password" placeholder="Password..." /><br>
<button id="chatLoginBtn">Login / Register</button>
</div>
<div id="chatWindow">
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(function () {
var socket = io();
$(document).ready(function(){
$("#chatWindow").hide();
$("#chatLoginBtn").click(function(){
socket.emit('loginForm', {
username: $("#username").val(),
password: $("#password").val()
});
});
});
socket.on('returnValue', function(msg) {
var html = '<ul id="messages"></ul>' +
'<form id="sendMsg" action="">' +
'<input id="m" autocomplete="off" /><button>Send</button>' +
'</form>';
$("#chatLogin").html("").hide();
$("#chatWindow").html(html).show();
$('#sendMsg').submit(function(e) {
e.preventDefault(); // prevents page reloading
var time = Date.now();
var msg = $("#m").val();
var data = [time, msg];
socket.emit('chat', data);
$('#m').val('');
return false;
});
});
socket.on('chat', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
</body>
</html>
index.js
var app = require('express')();
var http = require('http').createServer(app);
var phpPass = require('node-php-password');
var mysql = require('mysql');
var io = require('socket.io')(http);
var cookieParser = require('cookie-parser');
var session = require('express-session');
// DECLARE the variables we will be using
// These does not change
let userCount = 0;
// These are declared to be later set
var displayName;
var userDataID;
// POOL MySQL Connection
var pool = mysql.createPool({
connectionLimit : 100,
host : 'localhost',
user : 'root',
password : '....',
port : '3306',
database : '....',
debug : false
});
// session & cookieParser
/*var sessionMiddleware = session({
secret: "keyboard cat"
});
io.use(function (socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.use(cookieParser());*/
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
var hashPassword;
function checkUser(user, Password, userID) {
pool.getConnection(function(error,connection) {
connection.query("SELECT password FROM accounts WHERE `username` = '"+user+"' LIMIT 1",function(error,rows){
if (!error) {
var hashPassword = rows[0].password;
if (phpPass.verify(Password, hashPassword)) {
console.log(Password);
console.log(hashPassword);
console.log("Went well");
// UPDATE user database with current socketID
connection.query("UPDATE accounts SET `socketID` = '"+userID+"' WHERE `username` = '"+user+"'",function(error,result){
connection.release();
if (!error) {
connection.query("SELECT id,displayName,username,email,fullName,dateofBirth,created,lastSignedIn FROM accounts WHERE socketID = '"+userID+"' LIMIT 1",function(error,userData){
if (!error) {
displayName = userData[0].displayName;
userDataID = userData[0].id;
console.log("Current user: " + userData[0].displayName);
} else {
console.log("Error" + error);
}
});
console.log("No error" + result);
} else {
console.log("We found error" + error);
}
});
// send to function to gather all needed info from database and save for the current session
return true;
} else {
console.log("Wrong pass");
return false;
}
console.log(hashPassword);
} else {
console.log(error);
return false;
}
});
connection.on('error', function(error) {
});
});
return true;
};
io.on('connection', (socket) => {
var req = socket.request;
var userID = socket.id;
// When connection is inited
userCount++;
console.log('User connected' + userCount);
// Take the data from login and pass to check if it is valid
socket.on("loginForm", function(data){
const user = data.username,
pass = data.password;
//console.log(checkUser(user, pass));
if (checkUser(user, pass, userID)) {
io.emit('returnValue', 'hi');
}
});
function joinRoom(room) {
socket.join(room);
console.log("Joined " + room);
return io.emit('chat', "Joined new room " + room);
}
socket.on('join', (data) => {
socket.join(data);
console.log("Joined " + data);
});
socket.on('chat', (data) => {
/* Array: Data;
[0] Time
[1] Message
[2] socketID
[3] User
*/
var msg = data[1];
var time = data[0];
// Calc time
var date = new Date(time);
var hours = date.getHours();
var minutes = date.getMinutes();
var formatted = hours + ":" + minutes;
if (minutes < 10) return minutes = "0" + minutes;
var dateFormatted = "[" + formatted + "] ";
//data.push(user);
pool.getConnection(function(error,connection) {
connection.query("INSERT INTO `chat_messages` (userID, socketID, message, time) VALUES ('"+userDataID+"', '"+userID+"', '"+msg+"', '"+time+"')",function(error,rows){
connection.release();
if (!error) {
console.log("Success");
} else {
console.log(error);
}
});
});
if (msg.startsWith('/me')) return io.emit('chat', dateFormatted + displayName + msg.substring(3));
if (msg.startsWith('/join')) return joinRoom(msg.substring(6));
if (msg.startsWith('/rooms')) return console.log(io.sockets.adapter.rooms);
return io.emit('chat', dateFormatted + displayName + ' said: ' + msg);
//console.log(displayName + 'said:' + msg);
});
// When user disconnects
socket.on('disconnect', () => {
userCount--;
console.log('User disconnected!' + userCount);
});
});
http.listen(3000, () => {
console.log('Listening on *:3000');
});
I do not get any errors and it counts the number of users correctly
The problem is that the user first logged in gets switched to the last logged in user
How do I make the user session unique and so multiple clients can be logged in into different accounts?
I noticed an issue: var userDataID;
It's a global variable. Each time a new user log ing, the userDataID will be updated. It's always the ID of the newest logged user. Then, all new messages will be stored in the database with the userDataID.
EX:
- Log in by account A on window, the userDataID = 1;
- send some messages to server, these message will be stored with userID = 1
- Log in by account B on iphone, the userDataID will be updated, it's = 2 now.
- send some messages from windown & iphone. all these message will be stored with userID 2.
I think that's the error you got.
Should store userID in cookie or session.
Related
I'm all new to pug (jade).
I've got the following markup which does exactly what I want for the html part:
doctype html
html(lang="en")
head
title= "Project BOT"
body
h1 My project BOT
.container
.row
- for (var i=0; i<5; i++){
.item col-md-3 col-sm-12 #content
.card
.front
p.telegram_id
p.restaurant_name
p.discount
p.timestamp
button
.back
- }
I've got a nodejs file where I establish connection to a database and just output the DB contents. Looks as follows:
// mysql connection credentials
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'host',
user: 'user',
password: 'pass',
database: 'dbname'
});
// connect to database
connection.connect(function (err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
connection.query('SELECT * from botrequests',
function (error, results, fields) {
if (error) throw error;
console.log(results);
});
What I wanna do is to output database fields in the for loop I've got in pug. What's the right (or the possible) way to do so?
Loop is gonna look like:
- for (var i=0; i<results.length; i++){
.item col-md-3 col-sm-12 #content
.card
.front
p.telegram_id results[i].id
p.restaurant_name results[i].name
p.discount results[i].discount
p.timestamp results[i].time
button
.back
- }
Thanks!
Simple server using express:
var express = require('express');
var app = express();
app.set("view engine","jade")
app.get('/', function (req, res) {
// mysql connection credentials
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'host',
user: 'user',
password: 'pass',
database: 'dbname'
});
// connect to database
connection.connect(function (err) {
if (err) {
return err;
}
console.log('connected as id ' + connection.threadId);
connection.query('SELECT * from botrequests',
function (error, results, fields) {
if (error) throw error;
res.render('JadeFileName', { results: results });
});
});
});
Jade can then loop through items internally:
if results && results.length
each r in results
.item col-md-3 col-sm-12 #content
.card
.front
p.telegram_id #{r.id}
p.restaurant_name #{r.name}
p.discount #{r.discount}
p.timestamp #{r.time}
button
.back
I am newbie to webRTC. I tried to create a Chat application, sending a simple text message.
But getting this error:
Uncaught DOMException: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open'
at HTMLButtonElement.
Here is my code.
index.html
<div class = "row">
<div class = "col-md-4 col-md-offset-4">
<h2> Please sign in</h2>
<input type = "email" id = "usernameInput"
class = "form-control formgroup" placeholder = "Enter Name"
required = "" autofocus = "" title="please Enter name">
<button id = "loginBtn" class = "btn btn-lg btn-primary btnblock">
Sign in</button>
</div>
</div>
</div>
<div id = "callPage" class = "call-page container">
<div class = "row">
<div class = "col-md-4 col-md-offset-4 text-center">
<div class = "panel panel-primary">
<div class = "panel-heading">Text chat</div>
<div id = "chatarea" class = "panel-body text-left"></div>
</div>
</div>
</div>
<div class = "row text-center">
<div class = "col-md-12">
<input id = "msgInput" type = "text" placeholder = "Enter message" />
<button id = "sendMsgBtn" class = "btn-success btn">Send</button>
</div>
</div>
</div>
<script >
var name;
var connectedUser;
var conn = new WebSocket('ws://localhost:8000');
conn.onopen = function () {
console.log("Connected to the signaling server");
};
//when we got a message from a signaling server
conn.onmessage = function (msg) {
console.log("Got message", msg.data);
var data =JSON.parse( msg.data);
// console.log(data.type);
switch(data.type) {
case "login":
handleLogin(data.success);
break;
//when somebody wants to call us
case "offer":
handleOffer(data.offer, data.name);
break;
case "answer":
handleAnswer(data.answer);
break;
//when a remote peer sends an ice candidate to us
case "candidate":
handleCandidate(data.candidate);
console.log('candidate');
break;
case "leave":
handleLeave();
break;
default:
break;
}
};
conn.onerror = function (err) {
console.log("Got error", err);
};
//alias for sending JSON encoded messages
function send(message) {
//attach the other peer username to our messages
if (connectedUser) {
message.name = connectedUser;
}
conn.send(JSON.stringify(message));
};
var loginPage = document.querySelector('#loginPage');
var usernameInput = document.querySelector('#usernameInput');
var loginBtn = document.querySelector('#loginBtn');
var callPage = document.querySelector('#callPage');
var callToUsernameInput = document.querySelector('#callToUsernameInput');
// var callBtn = document.querySelector('#callBtn');
// var hangUpBtn = document.querySelector('#hangUpBtn');
var msgInput = document.querySelector('#msgInput');
var sendMsgBtn = document.querySelector('#sendMsgBtn');
var chatArea = document.querySelector('#chatarea');
var yourConn;
var dataChannel;
callPage.style.display = "none";
// Login when the user clicks the button
loginBtn.addEventListener("click", function (event) {
name = usernameInput.value;
if (name.length > 0) {
send({
type: "login",
name: name
});
}
});
function handleLogin(success) {
if (success === false) {
alert("Ooops...try a different username");
} else {
loginPage.style.display = "none";
callPage.style.display = "block";
//using Google public stun server
var configuration = {
"iceServers": [{ "url": "stun:stun2.1.google.com:19302" }]
};
yourConn = new RTCPeerConnection(configuration,{optional: [{RtpDataChannels: true}]});
// Setup ice handling
yourConn.onicecandidate = function (event) {
console.log('enter into login');
if (event.candidate) {
send({
type: "candidate",
candidate: event.candidate
});
}
};
//creating data channel
dataChannel = yourConn.createDataChannel("channel", {reliable:true});
dataChannel.onerror = function (error) {
console.log("Ooops...error:", error);
};
//when we receive a message from the other peer, display it on the screen
dataChannel.onmessage = function (event) {
chatArea.innerHTML += connectedUser + ": " + event.data + "<br />";
};
dataChannel.onclose = function () {
console.log("data channel is closed");
};
}
};
//when we got an answer from a remote user
function handleAnswer(answer) {
yourConn.setRemoteDescription(new RTCSessionDescription(answer));
};
//when we got an ice candidate from a remote user
function handleCandidate(candidate) {
yourConn.addIceCandidate(new RTCIceCandidate(candidate));
};
//when user clicks the "send message" button
sendMsgBtn.addEventListener("click", function (event) {
var val = msgInput.value;
chatArea.innerHTML += name + ": " + val + "<br />";
//sending a message to a connected peer
dataChannel.send(val);
msgInput.value = "";
});
</script>
server.js
var WebSocket = require('ws').Server;
var Port= 8000;
//creating a websocket server at port 9090
var wss = new WebSocket({port: Port});
var fs=require('fs');
var http=require('http');
console.log("STARTED");
var server = http.createServer(function (req, resp) {
fs.readFile("index.html", function (error, pgResp) {
if (error) {
resp.write('Contents you are looking are Not Found');
} else {
resp.end(pgResp);
}
});
});
server.listen(3000);
//all connected to the server users
var users = {};
//when a user connects to our sever
wss.on('connection', function(connection) {
console.log("User connected");
//when server gets a message from a connected user
connection.on('message', function(message) {
var data;
//accepting only JSON messages
try {
data = JSON.parse(message);
} catch (e) {
console.log("Invalid JSON");
data = {};
}
//switching type of the user message
switch (data.type) {
//when a user tries to login
case "login":
console.log("User logged", data.name);
//if anyone is logged in with this username then refuse
if(users[data.name]) {
sendTo(connection, {
type: "login",
success: false
});
} else {
//save user connection on the server
users[data.name] = connection;
connection.name = data.name;
sendTo(connection, {
type: "login",
success: true
});
}
break;
case "offer":
//for ex. UserA wants to call UserB
console.log("Sending offer to: ", data.name);
//if UserB exists then send him offer details
var conn = users[data.name];
if(conn != null) {
//setting that UserA connected with UserB
connection.otherName = data.name;
sendTo(conn, {
type: "offer",
offer: data.offer,
name: connection.name
});
}
break;
case "answer":
console.log("Sending answer to: ", data.name);
//for ex. UserB answers UserA
var conn = users[data.name];
if(conn != null) {
connection.otherName = data.name;
sendTo(conn, {
type: "answer",
answer: data.answer
});
}
break;
case "candidate":
console.log("Sending candidate to:",data.name);
var conn = users[data.name];
if(conn != null) {
sendTo(conn, {
type: "candidate",
candidate: data.candidate
});
}
break;
case "leave":
console.log("Disconnecting from", data.name);
var conn = users[data.name];
conn.otherName = null;
//notify the other user so he can disconnect his peer connection
if(conn != null) {
sendTo(conn, {
type: "leave"
});
}
break;
default:
sendTo(connection, {
type: "error",
message: "Command not found: " + data.type
});
break;
}
});
//when user exits, for example closes a browser window
//this may help if we are still in "offer","answer" or "candidate" state
connection.on("close", function() {
if(connection.name) {
delete users[connection.name];
if(connection.otherName) {
console.log("Disconnecting from ", connection.otherName);
var conn = users[connection.otherName];
conn.otherName = null;
if(conn != null) {
sendTo(conn, {
type: "leave"
});
}
}
}
});
connection.send(JSON.stringify("Hello world"));
});
function sendTo(connection, message) {
connection.send(JSON.stringify(message));
}
I have searched many posts and tried removing "{optional: [{RtpDataChannels: true}]}" ,set reliable=false. But still facing the same problem.Is it the chrome version problem? I am using Version 62.0.3202.75 (Official Build) (32-bit) of chrome.
I'm using node.js and I get the error in the picture every single time a client disconnects (This happens when I just close the tab and I've also tried using socket.disconnect() on both the client and the server side)
here's my code
var io = require('socket.io').listen(4000);
var fs = require('fs');
io.sockets.on('connection', function(socket) {
socket.on('login', function(info)
{
fs.readFile("chatLog.txt", function(err, data)
{
if(err)
{
return console.error(err);
}
socket.emit('incomingMessage', data.toString());
});
socket.broadcast.emit('newUser', info);
});
socket.on('message', function(content) {
console.log(content);
io.sockets.emit('incomingMessage', content);
});
socket.on('logout', function(name)
{
socket.broadcast.emit('incomingMessage', "user: " + name + " has logged out");
//socket.disconnect();
});
});
can anyone tell me how to disconnect without having the server crash with that error?
client side HTML:
<html>
<head>
<!-- This is the websocket SERVER -->
<script src="http://localhost:4000/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</head>
<body>
<div id="loginDiv">
username: <input type="text" id = "userName"><br>
<input type = "button" id="login" value = "login" onClick="login()">
</div>
<div id="logoutDiv" style="visibility:hidden">
<input type = "button" id = "messageRedir" value = "send message" onClick= "gotoMessage()">
<input type = "button" id = "logout" value = "logout" onClick="logout()">
</div>
<div id="sendMessage" style="visibility:hidden">
<input type = "text" id="messageBox"><br>
<input type = "button" value="send message" onClick="sendMessage()">
<input type = "button" value = "cancel" onClick="back">
</div>
<div id="msg"></div>
</body>
</html>
Client side JS:
var userName = null;
var socket = null;
function login()
{
socket = io.connect('http://localhost:4000');
userName = document.getElementById('userName').value;
document.getElementById("loginDiv").style.visibility = "hidden";
document.getElementById("logoutDiv").style.visibility = "visible";
socket.emit('login', userName+ ' has connected');
// Attach event handler for event fired by server
socket.on('incomingMessage', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
socket.on('newUser', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
}
function logout()
{
document.getElementById("loginDiv").style.visibility = "visible";
document.getElementById("logoutDiv").style.visibility = "hidden";
document.getElementById('msg').innerHTML = "";
socket.emit('logout', userName);
socket.disconnect();
socket = null;
}
function gotoMessage()
{
document.getElementById("loginDiv").style.visibility = "hidden";
document.getElementById("msg").style.visibility = "hidden";
document.getElementById("sendMessage").visibility = "visible";
}
function back()
{
document.getElementById("loginDiv").style.visibility = "visible";
document.getElementById("msg").style.visibility = "visible";
document.getElementById("sendMessage").visibility = "hidden";
}
function sendMessage()
{
var mess = document.getElementById('messageBox').value;
socket.emit('message', mess);
}
The problem is most likely in the logout function where you are using the socket (that is no longer active) to emit an event. You should use io.sockets.emit instead. I have some suggestions.
Instead of using the socket.emit('logout', username) event on the client side, use the built in logout event that gets fired when the user close the browser. That event is disconnect. You don't need to pass the username with each request either. You only need to pass it once with the login event. Then you can store the username on the server as a property of the socket.
Client Side
function login()
{
socket = io.connect('http://localhost:4000');
userName = document.getElementById('userName').value;
document.getElementById("loginDiv").style.visibility = "hidden";
document.getElementById("logoutDiv").style.visibility = "visible";
// just send the username
socket.emit('login', userName);
// Attach event handler for event fired by server
socket.on('incomingMessage', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
socket.on('newUser', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
}
function logout()
{
document.getElementById("loginDiv").style.visibility = "visible";
document.getElementById("logoutDiv").style.visibility = "hidden";
document.getElementById('msg').innerHTML = "";
socket.disconnect();
socket = null;
}
Server Side
io.sockets.on('connection', function(socket) {
socket.on('login', function(uxname)
{
// store username variable as property of the socket connection
// this way we can handle the disconnect message later
this.username = uxname;
fs.readFile("chatLog.txt", function(err, data)
{
if(err)
{
return console.error(err);
}
socket.emit('incomingMessage', data.toString());
});
socket.broadcast.emit('newUser', uxname);
});
socket.on('message', function(content) {
console.log(content);
io.sockets.emit('incomingMessage', content);
});
socket.on('disconnect', function(){
// don't use socket.broadcast.emit. at this point the socket is destroyed and you cant call events on it. That is most likely why you have the error.
// use io.sockets.emit instead
io.sockets.emit('incomingMessage', "user: " + this.username + " has logged out")
});
});
I'm trying to create a chat system, where a user can send message to everybody (and this message is displayed in the div with id "chat") and I've achieved this feature. Now I'd like to implement a private chat. A user can click on another user's name on the right column (which shows all logged users), once he clicked on a username a little window will appear (div with class "chatpopup") and in this window there is a submit button and an input text to be filled with a message, once submit button has been clicked the message should be sent to the other user.
This is what I have, if I click on a user (on the right side of the screen) the little window (chatpopup) is shown but when I try to submit the form inside this little window the app crashes.
I'd also like to receive some hints about building a private chat, for example how can I open a new window (with the message receive) in the client side of the user that should receive the message?
index.html
<html>
<head>
<title>Chat with socket.io and node.js</title>
<style>
#contentWrap
{
width:100%;
display: none;
}
#chatWrap {float: left; width:80%;}
#chat
{
height:500px;
width:96%;
border: 1px #000 solid;
padding-left:2%;
padding-right:2%;
}
#users
{
margin-left:82%; width:15%;
height:500px;
border: 1px #000 solid;
text-align:right;
}
#send-message {margin-top:3%; width:100%;}
#message {width:80%;}
.err1r{ padding-top:1%;
color: red;
}
.whisper{
color: gray;
font-style: italic;
}
p.sideusername:nth-child(even) {background-color:#FAFAFA; padding-bottom:5%; padding-top:5%;}
p.sideusername:nth-child(odd) {background-color: #f5f5f0; padding-bottom:5%; padding-top:5%;}
.chatpopup {width:350px; height: 250px; background-color:blue;}
#interlocutore {background-color:red; height: 30px; text-align: left;}
#msgspace {height:150px; background-color:yellow;}
</style>
</head>
<body>
<div id="nickWrap">
<p>Enter a username:</p>
<p id="nickError"></p>
<form id="setNick">
<input size="35" id="nickname"></input>
<input type="submit"></input>
</form>
</div>
<div id="contentWrap">
<div id="chatWrap">
<div id="chat"></div>
<form id="send-message">
<input size="35" id="message"></input>
<input type="submit"></input>
</form>
</div>
<div id="users"></div>
</div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
jQuery(function($){
var socket = io.connect();
var $nickForm = $('#setNick');
var $nickError = $('#nickError');
var $nickBox = $('#nickname');
var $users = $('#users');
var $messageForm = $('#send-message');
var $messageFormPopup = $('#send-message-popup');
var $messageBox = $('#message');
var $messageBoxPopup = $('#messagePopup');
var $chat = $('#chat');
$nickForm.submit(function(e){
e.preventDefault();
socket.emit('new user', $nickBox.val(), function(data){
if(data){
$('#nickWrap').hide();
$('#contentWrap').show();
} else{
$nickError.html('That username is already taken! Try again.');
}
});
$nickBox.val('');
});
socket.on('usernames', function(data){
$users.empty();
for(var i=0; i < data.length; i++){
$users.append('<p class="sideusername">' + data[i] + "</p>");
}
});
$messageForm.submit(function(e)
{
e.preventDefault();
socket.emit('send message', $messageBox.val(), function(data)
{
});
$chat.append('<span class="error">' + data + "</span><br/>");
$messageBox.val('');
});
$messageFormPopup.submit(function(e)
{
e.preventDefault();
socket.emit('send popup message', $messageBoxPopup.val(), function(dataPopup)
{
});
$messageBoxPopup.val('');
});
socket.on('load old msgs', function(docs){
for(var i=docs.length-1; i >= 0; i--){
displayMsg(docs[i]);
}
});
socket.on('new message', function(data){
displayMsg(data);
});
function displayMsg(data){
$chat.append('<span class="msg"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
}
socket.on('whisper', function(data){
$chat.append('<span class="whisper"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
});
$(document).on("click", ".closepopup", function() {
$(this).parents('.chatpopup').hide();
});
$(document).on("click", ".sideusername", function()
{
var interlocutore = $(this).text();
$chat.append('<div class="chatpopup"><table><tr><td id="interlocutore"></td><td><p class="closepopup">X</p></td></tr><tr><td colspan="2" id="msgspace"></td></tr><tr><td colspan="2"><form id="send-message-popup"> <input size="35" id="messagePopup"></input><input type="submit"></input></form></td></tr></table></div>');
$('#interlocutore').append(interlocutore);
});
});
</script>
</body>
</html>
app.js
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
mongoose = require('mongoose'),
users = {};
server.listen(3000);
mongoose.connect('mongodb://localhost/chat', function(err)
{
if(err)
console.log(err);
else console.log('Connected to mongodb!');
});
var chatSchema = mongoose.Schema(
{
nick: String,
msg: String,
created: {type: Date, default: Date.now}
});
var Chat = mongoose.model('Message', chatSchema);
app.get('/', function(req, res)
{
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket)
{
var query = Chat.find({});
query.sort('-created').limit(8).exec(function(err, docs)
{ // carico gli ultimi 8 messaggi in ordine di data
if(err) throw err;
socket.emit('load old msgs', docs);
});
socket.on('new user', function(data, callback)
{
if (data in users)
callback(false);
else
{
callback(true);
socket.nickname = data;
users[socket.nickname] = socket;
updateNicknames();
}
});
function updateNicknames()
{
io.sockets.emit('usernames', Object.keys(users));
}
socket.on('send message', function(data, callback)
{
var msg = data.trim();
var newMsg = new Chat({msg: msg, nick: socket.nickname});
newMsg.save(function(err)
{
if(err) throw err;
io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
});
socket.on('disconnect', function(data)
{
if(!socket.nickname) return;
delete users[socket.nickname];
updateNicknames();
});
});
socket.on('send popup message', function(data, callback)
{
/*var msgPopup = dataPopup.trim();
if (msgPopup !== "")
users[interlocutore].emit('whisper', {msg: msgPopup, nick: socket.nickname});
*/
var msg = data.trim()+" hello";
var newMsg = new Chat({msg: msg, nick: socket.nickname});
newMsg.save(function(err)
{
if(err) throw err;
io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
});
socket.on('disconnect', function(data)
{
if(!socket.nickname) return;
delete users[socket.nickname];
updateNicknames();
});
});
});
To create a private chat using socket.IO, you need to first understand how rooms in socket.IO work. You can find loads of tutorials. You can also see this post for help.
Now you need to extend this functionality to create a private chat system. In order to do so, you need to have an unique id for each client that is either connected or is online. socket.id is an unique key that each client gets upon joining the chat.
On the client side, you can emit a name along with the message to the server. You do so like this:
socket.emit('privateMessage', 'theUserName', message);
On the server side, you could manage an array of the users who are connected and save their unique usernames or id's.
var connectedClients = {};
So each time an user connects to the chat, (for which you are probably using the new user event), save the user's id in the connectedClients.
connectedClients[username] = socket.id;
Where username is the name that is sent to the server while an user is connecting to the chat system. (I hope you know how to do this. If not, do ask me.)
Then we make a listener to listen to the privateMessage event and emit to the message to that particular user, we do:
socket.on('privateMessage', function(to, message) {
var id = connectedClients[to];
io.sockets.socket(id).emit('sendPrivateMessage', socket.username, message);
});
Finally, on the client side, your listener for the sendPrivateMessage receives the message and you can update your view accordingly.
The idea is that the server saves each socket connected to it by the username: users[socket.nickname] = socket;
so whenever a user send a message to another user - you should emit an event - send to that the username of the other user - take the socket of that user and emit him a message:
client:
socket.emit('sendPrivate','someusername','message');
socket.on('privateMsg',function(from,msg){
//write private message from user 'from'
});
server:
socket.on('sendPrivate',function(to,msg){
users[to].emit('privateMsg',socket.username,msg);
});
first sorry for my bad english.
I'm trying to make a video call with WebRTC but it doesn't work.
I'm using node.js+socket.io+express for the server.
I appreciate any help or suggestions you can give me.
Thank you very much.
This is my code.
SERVER
var express = require('express')
, io = require('socket.io')
, app = express()
, server = require('http').createServer(app)
, io = io.listen(server);
server.listen(8080);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
var usuarios = [];
io.sockets.on('connection', function (socket) {
usuarios.push(socket);
console.log('Nuevo usuario conectado - ' + usuarios.length + ' en total');
socket.on('message', function (mensaje) {
usuarios.forEach(function (usuario) {
if (usuario != socket) {
usuario.send(mensaje);
}
});
});
socket.on('disconnect', function () {
console.log("Usuario desconectado");
// ...
});
});
CLIENT
<html>
<head>
<title>Cliente</title>
</head>
<body>
<video id='videolocal' autoplay style='width: 200px; height: 150px; border: 1px solid black;'></video>
<video id='videoremoto' autoplay style='width: 200px; height: 150px; border: 1px solid black;'></video>
<button type="button" onclick="iniciarCamara();">Iniciar Camara</button>
<button type="button" onclick="pararCamara();">Parar Camara</button>
<button type="button" onclick="conectar();">Conectar</button>
<button type="button" onclick="desconectar();">Desconectar</button>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
var videolocal = document.getElementById('videolocal');
var videoremoto = document.getElementById('videoremoto');
var streamlocal = null;
var pc = null;
var conectado = false;
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
socket.on('message', function (mensaje) {
var msg = JSON.parse(mensaje);
if (msg.type === 'oferta') {
pc.setRemoteDescription(pc.SDP_OFFER, new SessionDescription(msg.sdp));
responder();
} else if (msg.type === 'respuesta' && conectado) {
pc.setRemoteDescription(pc.SDP_ANSWER, new SessionDescription(msg.sdp));
} else if (msg.type === 'candidate' && conectado) {
var candidate = new IceCandidate(msg.label, msg.candidate);
pc.processIceMessage(candidate);
} else if (msg.type === 'desconectar' && conectado) {
//...
}
});
function responder() {
var oferta = pc.remoteDescription;
var respuesta = pc.createAnswer(oferta.toSdp(), {has_audio:true, has_video:true});
pc.setLocalDescription(pc.SDP_ANSWER, respuesta);
socket.send({type: 'respuesta', sdp: respuesta.toSdp()});
pc.startIce();
}
function crearPeerConnection() {
pc = new webkitPeerConnection00(null, iceCallback);
pc.addEventListener("addstream", anadirStreamRemoto, false);
pc.addEventListener("removestream", eliminarStreamRemoto, false);
function anadirStreamRemoto(event) {
videoremoto.src = window.webkitURL.createObjectURL(event.stream);
}
function eliminarStreamRemoto(event) {
videoremoto.src = "";
}
}
function iniciarCamara() {
navigator.getUserMedia({video: true, audio: true}, okCallback, errorCallback);
function okCallback(stream) {
videolocal.src = window.URL.createObjectURL(stream);
streamlocal = stream;
}
function errorCallback(error) {
alert("Error");
return;
}
}
function pararCamara() {
videolocal.src = "";
}
function iceCallback(candidate, bMore) {
if(candidate) {
socket.send({type: 'candidate', label: candidate.label, candidate: candidate.toSdp()});
}
}
function conectar() {
if (!conectado && streamlocal) {
crearPeerConnection();
conectado = true;
var oferta = pc.createOffer({has_audio:true, has_video:true});
pc.setLocalDescription(pc.SDP_OFFER, oferta);
socket.send({type: 'oferta', sdp: oferta.toSdp()});
pc.startIce();
} else {
alert("No se ha iniciado el stream local");
}
}
function desconectar() {
pc.close();
pc = null;
conectado = false;
}
</script>
</body>
ERROR
Uncaught SyntaxError: Unexpected token o localhost:25
(anonymous function) localhost:25
EventEmitter.emit socket.io.js:633
SocketNamespace.onPacket socket.io.js:2239
Socket.onPacket socket.io.js:1930
Transport.onPacket socket.io.js:1332
Transport.onData socket.io.js:1303
websocket.onmessage
Regards.
You have to send jsObjects while the socket.io method .send() sends messages, to serve data you need to use .emit() method, so you have to replace all
socket.send({...});
with:
socket.emit('message', {...})
and so you have to remove this line:
var msg = JSON.parse(mensaje);