webRTC datachannel is not working in chrome62 - node.js

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.

Related

How do I pass socket.io room name from one client to another?

I'm using socket.io v4 with NodeJS (Express).
So, the situation that I have is that I have a chat window for client and the client can enter their email and message. Now, I want to create a room based on that email and have another client join that room. My current implementation doesn't work. It creates the room but the other client is unable to join it.
Server Side Code:
io.of(/^\/dynamic-[a-zA-Z0-9]+$/).on("connection", (socket) => {
let email;
const namespace = socket.nsp.name;
let namespaceToCheck = namespace.split('-');
//console.log(namespaceToCheck[1])
User.findOne({apiKey: namespaceToCheck[1]})
.then((doc)=> {
if(namespaceToCheck[1] == doc.apiKey) {
socket.once("pass-email", (data) => {
io.of(namespace).emit("pass-email", data);
email = data;
})
console.log("Valid Connection");
socket.on("chat-message", (msg) => {
socket.join(email, function(){
//console.log(`Socket now in ${socket.rooms}`);
});
//console.log(msg);
console.log(socket.rooms);
Message.findOne({namespace: namespace})
.then((doc) => {
// console.log(doc);
doc.messages.push(msg);
doc.save().then((saved) => { return Promise.resolve(saved) });
})
// console.log(socket.handshake);
//io.of(namespace).sockets.in(data).emit("chat-message", msg);
console.log(email);
io.of(namespace).to(email).emit("chat-message", msg);
})
}
})
.catch((err)=> {
console.log(err);
})
});
Client Socket Code (from which I'm passing the email)
var chatSocket = io("http://localhost:3000/dynamic-8171d2a713d65c5edf81e45af4d14558a2c62275df05c73ca198a94d422e5948");
var chatBtn = document.querySelector('.chat-btn');
var input = document.querySelector('.chat-input');
var messages = document.querySelector(".messages");
var emailInputTag = document.querySelector(".email-input");
input.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
event.preventDefault();
if (input.value && emailInputTag.value) {
chatSocket.emit('create-room', emailInputTag.value);
//chatSocket.join(emailInputTag.value)
chatSocket.emit('chat-message', emailInputTag.value + ':' + input.value);
input.value = '';
}
}
});
chatBtn.addEventListener('click', function(e) {
e.preventDefault();
if (input.value && emailInputTag.value) {
chatSocket.emit('chat-message', emailInputTag.value + ':' + input.value);
input.value = '';
}
});
chatSocket.on('chat-message', function(msg) {
var item = document.createElement('div');
item.classList.add('msg');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
This is the rooms that this socket is in:
Client chat socket code (from which I want to receive room event and join the received room)
var chatSocket = io(`http://localhost:3000/dynamic-${ApiKey}`);
chatSocket.on("connect", function () {
console.log("Connected-test-succeeded");
// Connected, let's sign-up for to receive messages for this room
});
chatSocket.on("pass-email", (val) => {
console.log(val);
console.log("Listening");
});
var chatBtn = document.querySelector(".chat-btn");
var input = document.querySelector(".chat-input");
var messages = document.querySelector(".messages");
input.addEventListener("keypress", function (event) {
if (event.key === "Enter") {
event.preventDefault();
if (input.value) {
chatSocket.emit();
chatSocket.emit(
"chat-message",
"Owner" + ":" + input.value
);
input.value = "";
}
}
});
chatBtn.addEventListener("click", function (e) {
e.preventDefault();
if (input.value) {
chatSocket.emit(
"chat-message",
"Owner" + ":" + input.value
);
input.value = "";
}
});
chatSocket.on("chat-message", function (msg) {
console.log("Message received: " + msg);
var item = document.createElement("div");
item.classList.add("msg");
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
P.S: I know that the code is a bit messy but what I'm trying to do here is making a tawk.to clone so different namespace for each website url and the rooms are different in the said namespace for different users.

Invalid channel name - What could be causing this?

I am working on a site that will have a chatbox on it, basically it has a bunch of channels for different languages as well a channel for moderators and a channel for announcements.
I am getting an error [join] invalid channel name and since i'm so new with coding/developing I thought i'd share my code in hopes someone here can tell me where I messed something up.
CHAT.JS
var assert = require('assert');
var CBuffer = require('CBuffer');
var events = require('events');
var util = require('util');
var _ = require('lodash');
var debug = require('debug')('app:chat');
var db = require('./database');
var lib = require('./lib');
//Mute users by ip/username and store muted users in the database
var CHAT_HISTORY_SIZE = 100;
var SPECIAL_CHANNELS = {
all: {
desc: 'Channel where all messages are broadcasted, read only',
writable: false,
modsOnly: false
},
moderators: {
desc: 'Channel for moderators only, they are joinedds',
writable: true,
modsOnly: true
}
//This is the behaviour for all the other channels:
//defaultProps: {
// desc: '',
// writable: true,
// modsOnly: false
//}
};
// There is a mods channel for every channel
// The mods are joined to a channel called mod:channelName
function Chat(io) {
var self = this;
self.io = io;
// Number of connected clients
self.clientCount = 0;
/*
Collection of muted users.
key: Username
value: Object with the following fields
time: Date object when the user was muted
moderator: The username of the moderator that muted the user
timespec: Initial (nominal diff) time the user has been muted
end: Until when the user is muted
shadow: If the mute is a shadow mute
*/
self.muted = {};
io.on('connection', onConnection);
function onConnection(socket) { //socket.user is attached on the login middleware
debug('socket connection event received');
//Attach disconnect handler
socket.on('disconnect', function() {
--self.clientCount;
console.log('Client disconnect, left: ', self.clientCount);
debug('client disconnect');
});
//Join to a Room
socket.on('join', function(channelName) {
debug('join event received from user %s', socket.user ? socket.user.username : '~guest~');
self.join(socket, channelName);
});
//Register the message event
socket.on('say', function(message, isBot, customChannelName) {
self.onSay(socket, message, isBot, customChannelName);
});
++self.clientCount;
console.log('Client joined: ', self.clientCount, ' - ', socket.user ? socket.user.username : '~guest~'); //TODO: Add ip address
}
events.EventEmitter.call(self); //Call event emitter 'constructor' function
}
util.inherits(Chat, events.EventEmitter);
Chat.prototype.join = function(socket, channelName) {
var self = this;
var moderator = socket.user && socket.user.moderator;
//Check channelName variable and avoid users to join the mods channel
**if(isChannelNameInvalid(channelName) || isChannelNameModsOnly(channelName))
return sendError(socket, '[join] Invalid channel name');**
//Check if the channel is moderators only
if(SPECIAL_CHANNELS.hasOwnProperty(channelName))
if(SPECIAL_CHANNELS[channelName].modsOnly && !moderator)
return sendError(socket, '[join] This channel is moderators only');
//Check if the user was joined to another room before, if it was leave that room
if(socket.currentChannel)
socket.leave(socket.currentChannel);
//If mod leave the mods channel for this channel
if(socket.modCurrentChannel)
socket.leave(socket.modCurrentChannel);
//Save the name of the current room in the socket, this can also be used to check if the user is joined into a channel
socket.currentChannel = channelName;
//Get user history of a room and send it to the user
self.getHistory(channelName, function(err, history) {
//If we couldn't reach the history send an empty history to the user
if(err) {
history = [];
}
var res = {
history: history,
username: socket.user ? socket.user.username : null,
channel: channelName,
moderator: moderator
};
//Actually join the socket.io room
socket.join(channelName);
//If the user is mod and is not on the mods channel join him to the channel mod:channelName
if(moderator && channelName !== 'moderators') {
var chan = 'mod:'+channelName;
socket.join(chan);
socket.modCurrentChannel = chan;
}
//Return join info to the user
socket.emit('join', res);
});
};
Chat.prototype.onSay = function(socket, message, isBot, customChannelName) {
if (!socket.user)
return sendError(socket, '[say] you must be logged in to chat');
if (!socket.currentChannel)
return sendError(socket, '[say] you must be joined before you can chat');
//Check if the message is for a custom channel
var channelName;
if(customChannelName)
if(isChannelNameInvalid(customChannelName))
return sendError(socket, '[say] invalid channel name');
else
channelName = customChannelName;
else
channelName = socket.currentChannel;
//Check if the message is for a non writable channel ('all')
if(SPECIAL_CHANNELS.hasOwnProperty(channelName) && !SPECIAL_CHANNELS[channelName].writable)
return sendErrorChat(socket, 'The all channel is read only');
//Message validation
message = message.trim();
if (typeof message !== 'string')
return sendError(socket, '[say] no message');
if (message.length == 0 || message.length > 500)
return sendError(socket, '[say] invalid message size');
var cmdReg = /^\/([a-zA-z]*)\s*(.*)$/;
var cmdMatch = message.match(cmdReg);
if (cmdMatch) //If the message is a command try to execute it
this.doChatCommand(socket.user, cmdMatch, channelName, socket);
else //If not broadcast the message
this.say(socket, socket.user, message, channelName, isBot);
};
Chat.prototype.doChatCommand = function(user, cmdMatch, channelName, socket) {
var self = this;
var cmd = cmdMatch[1];
var rest = cmdMatch[2];
switch (cmd) {
case 'shutdown':
return sendErrorChat(socket, '[shutdown] deprecated feature boss');
case 'mute':
case 'shadowmute':
if (user.moderator) {
var muteReg = /^\s*([a-zA-Z0-9_\-]+)\s*([1-9]\d*[dhms])?\s*$/;
var muteMatch = rest.match(muteReg);
if (!muteMatch)
return sendErrorChat(socket, 'Usage: /mute <user> [time]');
var username = muteMatch[1];
var timespec = muteMatch[2] ? muteMatch[2] : "30m";
var shadow = cmd === 'shadowmute';
self.mute(shadow, user, username, timespec, channelName,
function (err) {
if (err)
return sendErrorChat(socket, err);
});
} else {
return sendErrorChat(socket, '[mute] Not a moderator.');
}
break;
case 'unmute':
if (user.moderator) {
var unmuteReg = /^\s*([a-zA-Z0-9_\-]+)\s*$/;
var unmuteMatch = rest.match(unmuteReg);
if (!unmuteMatch)
return sendErrorChat(socket, 'Usage: /unmute <user>');
var username = unmuteMatch[1];
self.unmute(
user, username, channelName,
function (err) {
if (err) return sendErrorChat(socket, err);
});
}
break;
default:
sendErrorChat(socket, 'Unknown command ' + cmd);
break;
}
};
Chat.prototype.getHistory = function (channelName, callback) {
if(channelName === 'all')
db.getAllChatTable(CHAT_HISTORY_SIZE, fn);
else
db.getChatTable(CHAT_HISTORY_SIZE, channelName, fn);
function fn (err, history) {
if(err) {
console.error('[INTERNAL_ERROR] got error ', err, ' loading chat table');
return callback(err);
}
callback(null, history);
}
};
Chat.prototype.say = function(socket, user, message, channelName, isBot) {
var self = this;
var date = new Date();
isBot = !!isBot;
var msg = {
date: date,
type: 'say',
username: user.username,
role: user.userclass,
message: message,
bot: isBot,
channelName: channelName
};
//Check if the user is muted
if (lib.hasOwnProperty(self.muted, user.username)) {
var muted = self.muted[user.username];
if (muted.end < date) {
// User has been muted before, but enough time has passed.
delete self.muted[user.username];
} else if (muted.shadow) {
// User is shadow muted. Echo the message back to the
// user but don't broadcast.
self.sendMessageToUser(socket, msg);
return;
} else {
self.sendMessageToUser(socket, {
date: date,
type: 'info',
username: user.username,
role: user.userclass,
message: 'You\'re muted. ' + lib.printTimeString(muted.end - date) + ' remaining',
bot: false,
channelName: channelName
});
return;
}
}
self.sendMessageToChannel(channelName, msg, user.id);
};
/** Send a message to the user of this socket **/
Chat.prototype.sendMessageToUser = function(socket, msg) {
socket.emit('msg', msg);
};
/** Send a message to a channel and to the all channel and store it in the database **/
Chat.prototype.sendMessageToChannel = function(channelName, msg, userID) {
console.assert(msg.hasOwnProperty('bot') && msg.date, msg.hasOwnProperty('message') && msg.type);
this.io.to(channelName).emit('msg', msg);
this.io.to('all').emit('msg', msg);
this.saveChatMessage(userID, msg.message, channelName, msg.bot, msg.date);
};
Chat.prototype.saveChatMessage = function(userId, message, channelName, isBot, date) {
db.addChatMessage(userId, date, message, channelName, isBot, function(err) {
if(err)
console.error('[INTERNAL_ERROR] got error ', err, ' saving chat message of user id ', userId);
});
};
Chat.prototype.mute = function(shadow, moderatorUser, username, time, channelName, callback) {
var self = this;
var now = new Date();
var ms = lib.parseTimeString(time);
var end = new Date(Date.now() + ms);
// Query the db to make sure that the username exists.
db.getUserByName(username, function(err, userInfo) {
if (err) {
if(typeof err === 'string') //USERNAME_DOES_NOT_EXIST
callback(err);
else
console.error('[INTERNAL_ERROR] got error ', err, ' muting user ', userInfo.username);
return;
}
assert(userInfo);
// Overriding previous mutes.
self.muted[userInfo.username] = {
date: now,
moderator: moderatorUser.username,
timespec: time,
end: end,
shadow: shadow
};
var msg = {
date: now,
type: 'mute',
message: null,
moderator: moderatorUser.username,
username: userInfo.username,
timespec: time,
shadow: shadow,
bot: false
};
//If mute shadow inform only mods about it
if (shadow) {
self.io.to('moderators').emit('msg', msg);
self.io.to('mod:'+channelName).emit('msg', msg);
//If regular mute send mute message to the channel
} else {
self.io.to(channelName).emit('msg', msg);
self.io.to('moderators').emit('msg', msg);
}
callback(null);
});
};
Chat.prototype.unmute = function(moderatorUser, username, channelName, callback) {
var self = this;
var now = new Date();
if (!lib.hasOwnProperty(self.muted, username))
return callback('USER_NOT_MUTED');
var shadow = self.muted[username].shadow;
delete self.muted[username];
var msg = {
date: now,
type: 'unmute',
message: null,
moderator: moderatorUser.username,
username: username,
shadow: shadow,
bot: false
};
//If mute shadow inform only mods about it
if (shadow) {
self.io.to('moderators').emit('msg', msg);
self.io.to('mod:'+channelName).emit('msg', msg);
//If regular mute send mute message to the channel
} else {
self.io.to(channelName).emit('msg', msg);
self.io.to('moderators').emit('msg', msg);
}
callback(null);
};
//Send an error to the chat to a client's socket
function sendErrorChat(socket, message) {
socket.emit('msg', {
date: new Date(),
type: 'error',
message: message
});
}
//Send an error event to a client's socket
function sendError(socket, description) {
console.warn('Chat client error ', description);
socket.emit('err', description);
}
function isChannelNameInvalid(channelName) {
return (typeof channelName !== 'string' || channelName.length < 1 || channelName.length > 100);
}
function isChannelNameModsOnly(channelName) {
return /^mod:/.test(channelName);
}
module.exports = Chat;
Well, I may be wrong, but I feel like that's not a piece of code you wrote, so you lack the deep knowledge of what's going on behind the hood. I'd suggest you to start something 100% from scratch without copying from tutorials to build a more solid knowledge of the tech you're using, but you're free to follow any path you prefer. Anyway, the error is clearly given from the method :
function isChannelNameInvalid(channelName) {
return (typeof channelName !== 'string' || channelName.length < 1 || channelName.length > 100);
}
So I guess you should give us a bit more insight on the channel name you used.

Host signalling server on heroku

I have built a signalling server using webrtc, nodejs, web-socket.
I am able to run the server locally but i want to host the server on heroku.
O have looked all over the internet but i cannot find anything relevant.
How can i host this server on Heroku?
Here is my code
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: 9090});
var users = {};
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("Hello world");
});
function sendTo(connection, message) {
connection.send(JSON.stringify(message));
}
Above is the code sample of server.js file.
Any help will be appreciated?
Here it is:
Step1: Push you code on github.
Before pushing make changes in your package.json.
Package.json is really important file to run your server on any cloud. Mainly start script, dependencies and node version is important.
Also in your code use process.env.PORT instead of any hard coded port number.
Step2: Create a heroku project through cli.
Now push you branch on heroku.
I know this is pretty brief steps. But I can help you more. If you are able to do it then good, otherwise I can help you in detail.

node.js error upon client disconnect

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")
});
});

Underscore _.contains method always failed inside mongoose promise query

Hi im using mongoose query inside socket.io event, so far so good. I want to check if a user is a member to a private room then fetch messages. So i use underscore method _.contains() but is always return false. I don't know what wrong with the code cuz logging both list and checked item it should return true
socket.on('add user', function (data) {
var username = data.username;
var userId = data.userId;
var currentroom = data.room ? data.room : '559c02cfd2ad52cc276b7491';
// we store the username in the socket session for this client
socket.username = username;
socket.userid = userId;
// add the client's username to the global list
usernames[username] = username;
++numUsers;
socket.emit('login', {
numUsers: numUsers
});
var room = new roomModel();
return room.getRoomParticipants(currentroom)
.then(function(res) {
console.log('checking room');
console.log(res);
if (!res) {
throw new Error('Couldn\'t get room participants!');
}
res = res[0];
var participants = res.participants;
return participants;
})
.then(function(participants) {
if (!_.contains(participants, socket.userid)) {
console.log('have failed');
return null;
}
_.each(participants, function(item) {
var user = new userModel();
user.getById(item)
.then(function(res) {
if (res) {
rommates[res._id] = res;
}
})
});
return roommates;
})
.then(function(participants) {
var message = new messageModel();
message.roomMessages(currentroom, msgLimit)
.then(function(res) {
_.each(res, function(item) {
var data = {};
var user = rommates[res._id];
data.username = user.username;
data.message = item.msg;
data.time = item.created_at;
socket.emit('new message', data);
});
});
})
.then(null, function(err) {
logger.debug(err);
});
});
Solved it by replacing
if (!_.contains(participants, socket.userid)) {
return null;
}
with
var participants = _.object(res.participants);
var allowed = _.find(res.participants, function(item) {
return item == socket.userid;
});
if (!allowed) {
throw new Error('User ' + socket.userid + ' is not allowed to room ' + currentroom);
}

Resources