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>
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();
}
});
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.
Related
I am new to the NodeJs. I have created a simple application using socket.io. I know that I can use ExpressJs framework but I am not getting overall idea as to how to separate the code and divide them into multiple pages so that debugging and maintenance is easily.
I am not understanding how to structure the code and where to write the socket.io code or any other NodeJs code in general.
Should I create new folder and files? If yes then how?
My code: app.js
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var ent = require('ent');
var fs = require('fs');
var cntActiveProductSupport = 0;
var cntActiveCustomer = 0;
var support_socket_id = '';
app.get('/',function (req, res) {
res.sendFile(__dirname+'/index.html');
});
app.get('/product_support',function (req, res) {
res.sendFile(__dirname+'/admin.html');
});
io.sockets.on('connection',function(socket,username){
//Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id
console.log(socket.id);
//total number of connections
console.log(io.engine.clientsCount);
socket.on('support_connected',function(username){
username = ent.encode(username);
socket.username = username;
socket.broadcast.emit('support_connected',username);
//get socket id of all connected sockets
Object.keys(io.sockets.sockets).forEach(function(id) {
console.log("ID:",id) // socketId
});
cntActiveProductSupport++;
support_socket_id = socket.id;
});
socket.on('new_client',function(username){
var client_socket_id = socket.id;
username = ent.encode(username);
socket.username = username;
socket.broadcast.emit('new_client',{ username: username, socket_id: socket.id, support_socket_id: support_socket_id });
socket.to(client_socket_id).emit('client_connected',{ username: username, support_socket_id: support_socket_id });
cntActiveCustomer++;
});
socket.on('message',function(data){
//socket.disconnect(true); use this if you want to disconnect client from server
//client which sent the message
var client_socket_id = socket.id;
var message = ent.encode(data.message);
// sending to individual socketid (private message)
//socket.to(socketId).emit('hey', 'I just met you');
socket.to(support_socket_id).emit('message', {username: socket.username,message:message, client_socket_id: client_socket_id});
});
socket.on('support_messaging',function(data){
message = ent.encode(data.message);
var customer_socket_id = data.customer_socket_id;
//socket.broadcast.emit('message', {username: socket.username,message:message});
// sending to individual socketid (private message)
socket.broadcast.to(customer_socket_id).emit('message', {username: socket.username,message:message});
//socket.to(socketId).emit('hey', 'I just met you');
//It's the same command as for rooms, that's because:
//"For your convenience, each socket automatically joins a room identified by this id."
});
socket.on('typing',function(username){
socket.broadcast.emit('typing', username);
});
socket.on('stopped-typing',function(){
socket.broadcast.emit('stopped-typing');
});
});
server.listen(8080);
My code: index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Real-time Super Chat!</title>
<style>
#zone_chat strong {
color: white;
background-color: black;
padding: 2px;
}
#writeup {
font-size:9px;
color: gray;
margin: 5px 0px;
}
</style>
</head>
<body>
<h4>Real-time Super Chat!</h4>
<form action="/" method="post" id="chat_form" autocomplete="off">
<input type="text" name="message" id="message" placeholder="Your message..." size="50" />
<input type="submit" id="send_message" value="Send" />
<input type="hidden" id="support_socket_id" value=""/>
<div id="writeup"></div>
</form>
<section id="chat_zone">
</section>
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
// Connecting to socket.io
var socket = io.connect('http://localhost:8080');
var socketConnected = false;
// The username is requested, sent to the server and displayed in the title
var username = prompt('What\'s your username?');
//var username = 'Deepak';
socket.emit('new_client', username);
document.title = username + ' - ' + document.title;
socket.on('connect', function() {
socketConnected = true;
console.log('Connected! ID: ' + socket.id);
});
socket.on('client_connected', function(data){
$('#support_socket_id').val(data.support_socket_id);
});
socket.on('disconnect', function() {
socketConnected = false;
console.log('Disconnected!');
});
// When a message is received it's inserted in the page
socket.on('message', function(data) {
insertMessage(data.username, data.message)
});
// When a new client connects, the information is displayed
// socket.on('new_client', function(username) {
// $('#chat_zone').prepend('<p><em>' + username + ' has joined the chat!</em></p>');
// });
socket.on('typing',function(username){
$('#writeup').html(username + ' is typing...');
});
socket.on('stopped-typing',function(){
$('#writeup').html('');
});
$(document).ready(function () {
$('#message').on('focus',function(){
socket.emit('typing',username);
});
$('#message').on('blur',function(){
socket.emit('stopped-typing',username);
});
// When the form is sent, the message is sent and displayed on the page
$('#chat_form').submit(function () {
var message = $('#message').val();
var support_socket_id = $('#support_socket_id').val();
socket.emit('message', { message:message, support_socket_id:support_socket_id }); // Sends the message to the others
insertMessage(username, message); // Also displays the message on our page
$('#message').val('').focus(); // Empties the chat form and puts the focus back on it
return false; // Blocks 'classic' sending of the form
});
});
// Adds a message to the page
function insertMessage(username, message) {
$('#chat_zone').prepend('<p><strong>' + username + '</strong> ' + message + '</p>');
}
</script>
</body>
</html>
You should create node modules in order to maintain the code structure. For example create routes folder and put all the route in there and separate them like users.js is a route file to cater routing related to user. As you are using socket.io you can create a separate module for socket.io functions and use them in your routes.
This link might help you: https://nodejs.org/api/modules.html
I hope it helps.
App Structure: routes, enter image description here
I'm following this tutorial to make a basic socket.io chatroom connected to mongodb. Here is the code:
const mongo = require('mongodb').MongoClient;
const client = require('socket.io').listen(3000).sockets;
// Connect to mongo
mongo.connect('mongodb://127.0.0.1/mongochat', function(err, db){
if(err){
throw err;
}
console.log('MongoDB connected...');
// Connect to Socket.io
client.on('connection', function(socket){
let chat = db.collection('chats');
// Create function to send status
sendStatus = function(s){
socket.emit('status', s);
}
// Get chats from mongo collection
chat.find().limit(100).sort({_id:1}).toArray(function(err, res){
if(err){
throw err;
}
// Emit the messages
socket.emit('output', res);
});
// Handle input events
socket.on('input', function(data){
let name = data.name;
let message = data.message;
// Check for name and message
if(name == '' || message == ''){
// Send error status
sendStatus('Please enter a name and message');
} else {
// Insert message
chat.insert({name: name, message: message}, function(){
client.emit('output', [data]);
// Send status object
sendStatus({
message: 'Message sent',
clear: true
});
});
}
});
// Handle clear
socket.on('clear', function(data){
// Remove all chats from collection
chat.remove({}, function(){
// Emit cleared
socket.emit('cleared');
});
});
});
});
The code runs and I get
(node:31737) DeprecationWarning: current URL string parser is
deprecated, and will be removed in a future version. To use the new
parser, pass option { useNewUrlParser: true } to MongoClient.connect.
MongoDB connected...
But when I try to get the html page in browser I get This 127.0.0.1 page can’t be found instead.
Here is the index.html page on the same folder as server.js that is supposed to be rendered but it does not:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<title>MongoChat</title>
<style>
#messages{height:300px;}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3 col-sm-12">
<h1 class="text-center">
MongoChat
<button id="clear" class="btn btn-danger">Clear</button>
</h1>
<div id="status"></div>
<div id="chat">
<input type="text" id="username" class="form-control" placeholder="Enter name...">
<br>
<div class="card">
<div id="messages" class="card-block">
</div>
</div>
<br>
<textarea id="textarea" class="form-control" placeholder="Enter message..."></textarea>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script>
(function(){
var element = function(id){
return document.getElementById(id);
}
// Get Elements
var status = element('status');
var messages = element('messages');
var textarea = element('textarea');
var username = element('username');
var clearBtn = element('clear');
// Set default status
var statusDefault = status.textContent;
var setStatus = function(s){
// Set status
status.textContent = s;
if(s !== statusDefault){
var delay = setTimeout(function(){
setStatus(statusDefault);
}, 4000);
}
}
// Connect to socket.io
var socket = io.connect('http://127.0.0.1:4000');
// Check for connection
if(socket !== undefined){
console.log('Connected to socket...');
// Handle Output
socket.on('output', function(data){
//console.log(data);
if(data.length){
for(var x = 0;x < data.length;x++){
// Build out message div
var message = document.createElement('div');
message.setAttribute('class', 'chat-message');
message.textContent = data[x].name+": "+data[x].message;
messages.appendChild(message);
messages.insertBefore(message, messages.firstChild);
}
}
});
// Get Status From Server
socket.on('status', function(data){
// get message status
setStatus((typeof data === 'object')? data.message : data);
// If status is clear, clear text
if(data.clear){
textarea.value = '';
}
});
// Handle Input
textarea.addEventListener('keydown', function(event){
if(event.which === 13 && event.shiftKey == false){
// Emit to server input
socket.emit('input', {
name:username.value,
message:textarea.value
});
event.preventDefault();
}
})
// Handle Chat Clear
clearBtn.addEventListener('click', function(){
socket.emit('clear');
});
// Clear Message
socket.on('cleared', function(){
messages.textContent = '';
});
}
})();
</script>
</body>
</html>
mongodb driver "mongodb": "^3.1.0-beta4",
mongodb database version v3.2.20
"socket.io": "^2.1.1"`
This problem bugs me for hours and I have no clues. So apprecite your help.
I have put together a video chat app using socket.io, webrtc, nodejs from this online tutorial from github but now I am getting errors when converting it to be used over https:
Request URL:https://telemed.caduceususa.com/socket.io/?EIO=3&transport=polling&t=1479396416422-0
Request Method:GET
Status Code:404 Not Found
Remote Address:10.9.2.169:443
Other errors I have gotten in this process are as follows:
When I try to declare a different PORT I get - ERR_SSL_PROTOCOL_ERROR,
When I try to declare port 80 or 8080 i get: ERR_CONNECTION_TIMED_OUT
Something is going wrong on this line inside socket.io.js:
xhr.send(this.data);
I am running a node.js server on Windows Server 2012 and I have set up IIS to serve up the server on PORT 80. I have created the subdomain https://telemed.caduceususa.com in DNS and have purchased a trusted SSL cert to run the site over HTTPS.
Here is the excerpt of code from the dev tools that contains the above line that is causing the error as well as my other code:
/**
* Creates the XHR object and sends the request.
*
* #api private
*/
Request.prototype.create = function(){
var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR };
// SSL options for Node.js client
opts.pfx = this.pfx;
opts.key = this.key;
opts.passphrase = this.passphrase;
opts.cert = this.cert;
opts.ca = this.ca;
opts.ciphers = this.ciphers;
opts.rejectUnauthorized = this.rejectUnauthorized;
var xhr = this.xhr = new XMLHttpRequest(opts);
var self = this;
try {
debug('xhr open %s: %s', this.method, this.uri);
xhr.open(this.method, this.uri, this.async);
if (this.supportsBinary) {
// This has to be done after open because Firefox is stupid
// https://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
xhr.responseType = 'arraybuffer';
}
if ('POST' == this.method) {
try {
if (this.isBinary) {
xhr.setRequestHeader('Content-type', 'application/octet-stream');
} else {
xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
}
} catch (e) {}
}
// ie6 check
if ('withCredentials' in xhr) {
xhr.withCredentials = true;
}
if (this.hasXDR()) {
xhr.onload = function(){
self.onLoad();
};
xhr.onerror = function(){
self.onError(xhr.responseText);
};
} else {
xhr.onreadystatechange = function(){
if (4 != xhr.readyState) return;
if (200 == xhr.status || 1223 == xhr.status) {
self.onLoad();
} else {
// make sure the `error` event handler that's user-set
// does not throw in the same tick and gets caught here
setTimeout(function(){
self.onError(xhr.status);
}, 0);
}
};
}
debug('xhr data %s', this.data);
xhr.send(this.data);
}
Here is the server.js file:
var fs = require('fs');
var hskey = fs.readFileSync('ssl/telemed_internal_server.key');
var hscert = fs.readFileSync('ssl/telemed_internal_cert.pem');
var ca = fs.readFileSync('ssl/telemed_internal_key.pem');
var credentials = {
ca: ca,
key: hskey,
cert: hscert
};
var static = require('node-static');
var https = require('https');
var util = require('util');
var file = new(static.Server)();
var app = https.createServer(credentials, function (req, res) {
file.serve(req, res);
}).listen(process.env.PORT || 80);
var io = require('socket.io').listen(app);
io.sockets.on('connection', function (socket){
// convenience function to log server messages on the client
function log(){
var array = [">>> Message from server: "];
for (var i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
// when receive sdp, broadcast sdp to other user
socket.on('sdp', function(data){
console.log('Received SDP from ' + socket.id);
socket.to(data.room).emit('sdp received', data.sdp);
});
// when receive ice candidate, broadcast sdp to other user
socket.on('ice candidate', function(data){
console.log('Received ICE candidate from ' + socket.id + ' ' + data.candidate);
socket.to(data.room).emit('ice candidate received', data.candidate);
});
socket.on('message', function (message) {
log('Got message:', message);
// for a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function (room) {
// join room
var existingRoom = io.sockets.adapter.rooms[room];
var clients = [];
if(existingRoom){
clients = Object.keys(existingRoom);
}
if(clients.length == 0){
socket.join(room);
io.to(room).emit('empty', room);
}
else if(clients.length == 1){
socket.join(room);
socket.to(room).emit('joined', room, clients.length + 1);
}
// only allow 2 users max per room
else{
socket.emit('full', room);
}
});
socket.on('error', function(error){
console.error(error);
})
});
Here is the main.js (config) file:
//my signalling server
var serverIP = "https://telemed.caduceususa.com/";
// RTCPeerConnection Options
var server = {
// Uses Google's STUN server
iceServers: [{
"url": "stun:stun4.l.google.com:19302"
},
{
url: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc#live.com'
}]
};
// various other development IPs
// var serverIP = "https://192.168.43.241:2013";
// var serverIP = "https://10.0.11.196:2013";
var localPeerConnection, signallingServer;
var btnSend = document.getElementById('btn-send');
var btnVideoStop = document.getElementById('btn-video-stop');
var btnVideoStart = document.getElementById('btn-video-start');
var btnVideoJoin = document.getElementById('btn-video-join');
var localVideo = document.getElementById('local-video');
var remoteVideo = document.getElementById('remote-video');
var inputRoomName = document.getElementById('room-name');
var localStream, localIsCaller;
btnVideoStop.onclick = function(e) {
e.preventDefault();
// stop video stream
if (localStream != null) {
localStream.stop();
}
// kill all connections
if (localPeerConnection != null) {
localPeerConnection.removeStream(localStream);
localPeerConnection.close();
signallingServer.close();
localVideo.src = "";
remoteVideo.src = "";
}
btnVideoStart.disabled = false;
btnVideoJoin.disabled = false;
btnVideoStop.disabled = true;
}
btnVideoStart.onclick = function(e) {
e.preventDefault();
// is starting the call
localIsCaller = true;
initConnection();
}
btnVideoJoin.onclick = function(e) {
e.preventDefault();
// just joining a call, not offering
localIsCaller = false;
initConnection();
}
function initConnection() {
var room = inputRoomName.value;
if (room == undefined || room.length <= 0) {
alert('Please enter room name');
return;
}
// start connection!
connect(room);
btnVideoStart.disabled = true;
btnVideoJoin.disabled = true;
btnVideoStop.disabled = false;
}
// WEBRTC STUFF STARTS HERE
// Set objects as most are currently prefixed
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection || window.msRTCPeerConnection;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription ||
window.webkitRTCSessionDescription || window.msRTCSessionDescription;
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia || navigator.msGetUserMedia;
window.SignallingServer = window.SignallingServer;
var sdpConstraints = {
optional: [],
mandatory: {
OfferToReceiveVideo: true,
}
}
function connect(room) {
// create peer connection
localPeerConnection = new RTCPeerConnection(server);
// create local data channel, send it to remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
// must add before calling setRemoteDescription() because then
// it triggers 'addstream' event
localPeerConnection.addStream(stream);
localStream = stream;
// show local video
localVideo.src = window.URL.createObjectURL(stream);
// can start once have gotten local video
establishRTCConnection(room);
}, errorHandler)
}
function establishRTCConnection(room) {
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
signallingServer.connect();
// a remote peer has joined room, initiate sdp exchange
signallingServer.onGuestJoined = function() {
trace('guest joined!')
// set local description and send to remote
localPeerConnection.createOffer(function(sessionDescription) {
trace('set local session desc with offer');
localPeerConnection.setLocalDescription(sessionDescription);
// send local sdp to remote
signallingServer.sendSDP(sessionDescription);
});
}
// got sdp from remote
signallingServer.onReceiveSdp = function(sdp) {
// get stream again
localPeerConnection.addStream(localStream);
trace(localStream)
// if local was the caller, set remote desc
if (localIsCaller) {
trace('is caller');
trace('set remote session desc with answer');
localPeerConnection.setRemoteDescription(new RTCSessionDescription(
sdp));
}
// if local is joining a call, set remote sdp and create answer
else {
trace('set remote session desc with offer');
localPeerConnection.setRemoteDescription(new RTCSessionDescription(
sdp), function() {
trace('make answer')
localPeerConnection.createAnswer(function(
sessionDescription) {
// set local description
trace('set local session desc with answer');
localPeerConnection.setLocalDescription(
sessionDescription);
// send local sdp to remote too
signallingServer.sendSDP(sessionDescription);
});
});
}
}
// when received ICE candidate
signallingServer.onReceiveICECandidate = function(candidate) {
trace('Set remote ice candidate');
localPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
}
// when room is full, alert user
signallingServer.onRoomFull = function(room) {
window.alert('Room "' + room +
'"" is full! Please join or create another room');
}
// get ice candidates and send them over
// wont get called unless SDP has been exchanged
localPeerConnection.onicecandidate = function(event) {
if (event.candidate) {
//!!! send ice candidate over via signalling channel
trace("Sending candidate");
signallingServer.sendICECandidate(event.candidate);
}
}
// when stream is added to connection, put it in video src
localPeerConnection.onaddstream = function(data) {
remoteVideo.src = window.URL.createObjectURL(data.stream);
}
}
function errorHandler(error) {
console.error('Something went wrong!');
console.error(error);
}
function trace(text) {
console.info(text);
}
Here is the signalling server:
function trace(text){
console.info(text);
}
// Connects to signalling server with given room and IP
// has methods to exchange SDP and ICE candidates
var SignallingServer = function(room, socketServer){
this.room = room;
this.socket = io.connect(socketServer);
this.socket.on('full', function (room){
trace('Room ' + room + ' is full');
this.onRoomFull(room);
}.bind(this));
this.socket.on('empty', function (room){
this.isInitiator = true;
trace('Room ' + room + ' is empty');
});
this.socket.on('join', function (room){
trace('Making request to join room ' + room);
});
this.socket.on('joined', function (room, numClients){
trace('New user has joined ' + room);
trace('Room has ' + numClients + ' clients');
//ask host to initiate sdp transfer
this.onGuestJoined();
}.bind(this));
this.socket.on('sdp received', function(sdp){
trace('Received SDP ');
trace(sdp);
this.onReceiveSdp(sdp);
}.bind(this));
this.socket.on('ice candidate received', function(candidate){
trace('Received ICE candidate ');
trace(candidate);
this.onReceiveICECandidate(candidate);
}.bind(this));
this.socket.on('log', function (array){
console.log.apply(console, array);
});
}
SignallingServer.prototype = {
connect: function(){
if (this.room !== '') {
trace('Joining room ' + this.room);
this.socket.emit('create or join', this.room);
}
},
close: function(){
trace('Disconnecting')
this.socket.disconnect();
},
sendSDP: function(sdp){
trace('sending sdp')
this.socket.emit('sdp', {
room: this.room,
sdp: sdp
});
},
sendICECandidate: function(candidate){
trace('sending ice candidate');
this.socket.emit('ice candidate', {
room: this.room,
candidate: candidate
});
},
onReceiveSdp: function(sdp){
trace('Placeholder function: Received SDP')
},
onGuestJoined: function(){
trace('Placeholder function: Guest joined room')
},
onReceiveICECandidate: function(candidate){
trace('Placeholder function: Received ICE candidate')
},
onRoomFull: function(room){
trace('Placeholder function: Room is full!');
}
}
window.SignallingServer = SignallingServer;
AND FINALLY THE HTML (CAN SOMEONE ALSO EXPLAIN WHAT LIVERELOAD.JS IS?):
<!doctype html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="">
<![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8" lang="">
<![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9" lang="">
<![endif]-->
<!--[if gt IE 8]>
<!-->
<html class="no-js" lang="">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<style>
body {
padding-top: 50px;
padding-bottom: 20px;
}
</style>
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"></script>
</head>
<body>
<!--[if lt IE 8]>
<p class="browserupgrade">
You are using an <strong>outdated</strong>
browser. Please
upgrade your browser
to improve your experience.
</p>
<![endif]-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">WebRTC Video Chat</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<!-- chatroom name form -->
<form class="navbar-form navbar-right form-inline">
<div class="form-group">
<input class="form-control" type="text" id="room-name" placeholder="Room name"/>
</div>
<button class="btn btn-primary" id="btn-video-start">Start</button>
<button class="btn btn-default" id="btn-video-join">Join</button>
<button class="btn btn-default" disabled id="btn-video-stop">Stop</button>
</form>
</div>
<!--/.navbar-collapse --> </div>
</nav>
<div class="container main">
<div class="row videos">
<div class="remote-video">
<video width="280" height="250" autoplay id="remote-video"></video>
</div>
<div class="local-video">
<video width="280" height="250" autoplay id="local-video" muted></video>
</div>
</div>
</div>
</div>
<!-- /container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/vendor/socket.io.js"></script>
<script src="js/main.js"></script>
<script src="js/signalling.js"></script>
<script src="//localhost:9010/livereload.js"></script>
</body>
</html>
i have a problem in this code (anyway sorry for my short Eng.)
i think this is a right code but don't know why it makes errors about indentation? any solutions or advices for this code :( ??
u can ignore the Korean that i wrote in this code
- if (!isSuccess)
script
alert('cannot make a chat room.');
location.href = '/enter';
- else
h3 room title :
span#roomName= roomName
input#leave(type='button', value='나가기')
#chatWindow(style='width:400px; height:400px; overflow:auto; border:1px solid #000; float:left; margin-right:10px;')
div(style='width:100px; height:400px; overflow:auto; border:1px solid #000;')
p 참가자
ul#attendants
each attendant in attendants
li(id='attendant-'+attendant)= attendant
form
span#myName #{nickName}
input(type='text', style='width:300px;')#message
input(type='submit', value='보내기')
script(type='text/javascript')
$(document).ready(function() {
var room = io.connect('/room');
var chatWindow = $('#chatWindow');
var messageBox = $('#message');
var myName = $('#myName').text();
var attendants = $('#attendants');
var showMessage = function(msg) {
chatWindow.append($('<p>').text(msg));
chatWindow.scrollTop(chatWindow.height());
};
room.on('connect', function() {
room.emit('join', {roomName:$('#roomName').text(), nickName:myName});
});
room.on('joined', function(data) {
if(data.isSuccess) {
showMessage(data.nickName + '님이 입장하셨습니다.');
attendants.append($('<li>')
.attr('id', 'attendant-'+data.nickName)
.text(data.nickName));
}
});
room.on('message', function(data) {
showMessage(data.nickName + ' : ' + data.msg);
});
room.on('leaved', function(data) {
showMessage(data.nickName + '님이 나가셨습니다.');
$('#attendant-'+data.nickName).remove();
});
$('form').submit(function(e) {
e.preventDefault();
var msg = messageBox.val();
if ($.trim(msg) !== '') {
showMessage(myName + ' : ' + msg);
room.json.send({nickName:myName, msg:msg});
messageBox.val('');
}
});
$('#leave').click(function(e) {
room.emit('leave', {nickName:myName});
location.href='/enter';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
If you want to add multiple lines/blocks when you're writing inline JS/CSS you need to add a .
script.
alert('cannot make a chat room.');
location.href = '/enter';
script(type='text/javascript').
$(document).ready(function() {
var room = io.connect('/room');
I thought the whole point of socket.io was to not have to worry about modern browsers? lol
Anyway, I am new to socket programming. I have a small app that simply mimics mouse movements.
You open several browsers and when you move the mouse, your actions are recorded in the other browsers. It moves a small square. Kinda cool. However, when I open it on my iPad (iOS6) nothing! Sockets isn't connecting. I even put an alert message in the connect event and nothing.
Works in IE, FF and Chrome just fine on my laptop. The only difference is that my dev machine uses localhost while the iPad uses my machine's IP. However, when I connect to my local IP on my laptop, it still works. Just not in Safari/iPad.
Here is my server.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs');
app.listen(80);
function handler(req, res) {
var file = __dirname + '/public/index.html';
fs.readFile(file,
function(err, data) {
if(err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
}
);
}
var rooms = ['abc', 'test1'];
var sockets = [];
io.sockets.on('connection', function(socket) {
sockets.push(socket);
socket.on('m', function(data) {
socket.broadcast.to(socket.room).emit('relay', {msg: 'MouseX: ' + data.x + ' MouseY: ' + data.y, x: data.x, y: data.y});
});
socket.on('join', function(room) {
socket.join(room);
socket.emit('updateStatus', {msg: 'Joined room ' + room});
console.log('Joined room ' + room);
});
});
Here is my client:
<!doctype html>
<html>
<head>
<style>
body {
padding: 40px;
}
#cursor {
background:white;
border:1px solid black;
color: white;
display: block;
height:24px;
padding:6px;
position:absolute;
width:24px;
z-index:20;
}
</style>
</head>
<body>
<input id='msg' type='text' size='100' /><br />
<input id='box' type='text' size='100' />
<div id='cursor'></div>
<script src='/socket.io/lib/socket.io.js'></script>
<script>
var socket = io.connect('http://localhost');
var b = document.getElementById('box');
var m = document.getElementById('msg');
var c = document.getElementById('cursor');
// join custom room
socket.on('connect', function() {
socket.emit('join', 'abc');
});
// update status messages from server
socket.on('updateStatus', function(data) {
m.setAttribute('value', data.msg);
});
socket.on('relay', function(data) {
b.setAttribute('value', data.msg);
c.style.left = parseInt(data.x) + 'px';
c.style.top = parseInt(data.y) + 'px';
});
document.onmousemove = function(event) {
event = event || window.event;
socket.emit('m', {x: event.clientX, y: event.clientY});
}
</script>
</body>
</html>
Localhost is local to the machine. You're IP should use a ip address or domain name:
something like:
io.connect('192.168.1.110');
or io.connect('test.myapp.com');