Handling byte streams in node.js - node.js

For education purposes I am creating a little chat with node.js using TCP.
I am using the windows console to connect with my node server but when I am typing all the characters are streamed one by one. They don't arive as strings. How can I manage to handle those streams so my users don't can write complete words.
My Code:
var net = require("net");
Array.prototype.remove = function(e) {
for (var i = 0; i < this.length; i++) {
if (e == this[i]) { return this.splice(i, 1); }
}
};
function Chatter(stream) {
this.name = null;
this.stream = stream;
}
var chatters = [];
var server = net.createServer(function(stream) {
var chatter = new Chatter(stream);
chatters.push(chatter);
stream.setTimeout(0);
stream.setEncoding("utf8");
stream.addListener("connect", function(){
stream.write("Hallo, wer bist du?:\n");
});
stream.addListener("data", function (data) {
if(chatter.name == null) {
chatter.name = data.match(/\S+/);
stream.write("....................\n");
chatters.forEach(function(c){
if (c != chatter) {
c.stream.write(chatter.name + " ist dem Chat beigetreten!\n");
}
});
return;
}
var command = data.match(/^\/(.*)/);
if (command) {
if (command[1] == 'users') {
chatters.forEach(function(c) {
stream.write("- " + c.name + "\n");
});
}
else if (command[1] == 'quit') {
stream.end();
}
}
chatters.forEach(function(c) {
if(c != chatter) {
c.stream.write(chatter.name + ": " + data);
}
});
});
stream.addListener("end", function(){
chatters.remove(chatter);
chatters.forEach(function(c) {
c.stream.write(chatter.name + " hat den Chat verlassen.\n");
});
stream.end();
});
});
server.listen(8000);
For the record that code is from this site
ADDITION:
setEncoding('utf8') is supposed to change the emiting of data, but it doesn't work for me :-(

The solution to your problem is to store all received characters in a buffer and when an END_OF_NICK character is encountered (say, \n), use the buffer as the name.
var buffer = ""; // stores received characters
stream.addListener("data", function (data) {
if(chatter.name == null) { // still receiving characters for the name
buffer += data; // append received characters to the buffer
if (buffer.indexOf('\n') == -1) return; // if there's no END_OF_NICK character, keep waiting for it
chatter.name = buffer.match(/\S+/); // use the name in the buffer
// ...
}

Related

How to migrate SSE chat node express to node hapi

I was testing a SSE node express chat in localhost.It was working perfectly. I was including a chat_server in a demo with hapijs as modular server...and it complain about the express syntax. How can I migrate the code to the right syntax in hapijs?
I am trying to solve changing writeHead and write methods because it's complaing about and adding stream package after searching answers in internet.
/*
* Request handlers
*/
function handleGetChat(req, res) {
console.log('handleGetChat received.');
// res(chatStream).code(200).type('text/event-stream').header('Connection', 'keep-alive').header('Cache-Control','no-cache');
// chatStream.write('\n');
(function(clientId) {
clients[clientId] = res;
clientNames[clientId] = req.params.name;
console.log('name {$req.params.name}');
req.on("close", () => {
delete clients[clientId];
actUserName = "";
sendText(clientNames[clientId] + " disconnected!", false);
delete clientNames[clientId];
});
})(++clientId);
sendText(req.params.name + " connected!", false);
let allMates = "";
for (cliId in clientNames) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(`logged in [${allMates}]`, false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(logged in [${allMates}], false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
let data = "";
let date = new Date();
let timestamp = `[${date.getHours()}:${date.getMinutes()}]`;
if (showUserName) {
data = `data: ${timestamp} <${actUserName}> ${text}\n\n`;
} else {
data = `data: ${timestamp} ${text}\n\n`;
}
//chatStream.push('data: ' + "\n\n");
}
};
function handleWriteChat(req, res) {
actUserName = req.body.name;
sendText(req.body.text);
res.json({ success: true });
}
The commented lines in the code above are the lines with syntax error in hapi. I was already changing the originals write and writeHead with chatstream.

WebRTC: Sound not muting - can anyone see an error?

I have inserted a mute button into my WebRTC Video chat page but I cannot get it to work. If I click it in the browser I get a console message that the sound has been muted but there is still sound.
The Constraints variables:
var constraints = {
video: true,
audio: true,
};
If I change audio to false here there will be no sound.
Code on Mute Button:
function muteVideoBtnClick() {
if(constraints.audio == true) {
constraints.audio = false;
console.log('Audio: ' + constraints.audio);
} else {
constraints.audio = true;
console.log('Audio: ' + constraints.audio);
}
}
The Only other place where the constraints variables are used:
function pageReady() {
uuid = uuid(); //CB Universal Unique Identifier
//CB Create the variables for local and remote video
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
//CB Create the connection using websocket (443 as it is a secure connection)
serverConnection = new WebSocket('wss://' + window.location.hostname + ':443');
serverConnection.onmessage = gotMessageFromServer;
// CB Checks thats getUserMedia works and then runs getUserMedia if it works and displays an error
//if it doesnt work
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
}
I would be very grateful if anyone has any suggestions.
Kind regards,
Claire
The Full code:
var localVideo;
var remoteVideo;
var peerConnection;
var uuid;
var rooms = [];//CB 31/07
var constraints = {
video: true,
audio: true,
};
var peerConnectionConfig = {
'iceServers': [
{'urls': 'stun:stun.services.mozilla.com'},
{'urls': 'stun:stun.l.google.com:19302'},
]
};
function pageReady() {
uuid = uuid(); //CB Universal Unique Identifier
//CB Create the variables for local and remote video
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
//CB Create the connection using websocket (443 as it is a secure connection)
serverConnection = new WebSocket('wss://' + window.location.hostname + ':443');
serverConnection.onmessage = gotMessageFromServer;
// CB Checks thats getUserMedia works and then runs getUserMedia if it works and displays an error
//if it doesnt work
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
}
//CB if it is possible to run gerUserMedia then gets the local video stream
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream); //Depreciated!!!!!
//localVideo.srcObject = stream;
}
//CB this function starts the call
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.onaddstream = gotRemoteStream;
//peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
//Added by CB for Pause Button 20/07
function pauseVideoBtnClick() {
var btn = document.getElementById("pause_video_btn");
if (isVideoPaused()) {
pauseVideo(false);
btn.innerHTML = "Pause Video";
} else {
pauseVideo(true);
btn.innerHTML = "Resume Video";
}
}
//Added by CB for Pause Button 20/07
function isVideoPaused() {
return !(localStream.getVideoTracks()[0].enabled);
}
//Added by CB for Pause Button 20/07
function pauseVideo (pause) {
localStream.getVideoTracks()[0].enabled = !pause;
};
//Added by CB for mute button 29/07 - DOESNT WORK YET
function muteVideoBtnClick() {
if(constraints.audio == true) {
constraints.audio = false;
console.log('Audio: ' + constraints.audio);
} else {
constraints.audio = true;
console.log('Audio: ' + constraints.audio);
}
}
//End of added code
function gotMessageFromServer(message) {
if(!peerConnection) start(false);
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if(signal.uuid == uuid) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function gotIceCandidate(event) {
if(event.candidate != null) {
serverConnection.send(JSON.stringify({'ice': event.candidate, 'uuid': uuid}));
}
}
function createdDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description).then(function() {
serverConnection.send(JSON.stringify({'sdp': peerConnection.localDescription, 'uuid': uuid}));
}).catch(errorHandler);
}
function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.src = window.URL.createObjectURL(event.stream);
//remoteVideo.src = event.stream;
}
function errorHandler(error) {
console.log(error);
}
// CB A UUID (Universal Unique Identifier) is a 128-bit number used to uniquely identify some object or entity on the Internet.
// Taken from http://stackoverflow.com/a/105074/515584
// Strictly speaking, it's not a real UUID, but it gets the job done here
function uuid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
You are changing the constraints to the getUserMedia call (after doing the call). You are not changing the resulting stream which is stored in the localStream variable. Try this:
localStream.getAudioTracks()[0].enabled = false;

node-irc with Twitch.TV duplicate message issue

My node-irc bot is sometimes repeating what it says in the chat. Sometimes it works perfectly; other times it repeats. I've looked all through my code and I cant find any recursion going on.
Connection function (with my listeners)
//connects the bot to the channel
this.connectToChannel = function(callback) {
console.log("Connection");
botInstance.connect();
botInstance.join(currentChannel, function(){
botInstance.say(currentChannel, initalConnectionMessage);
console.log("Joined");
callback();
});
botInstance.addListener("message", function(nick, to, text, message) {
if (text == lastText){
return; // you can i've tried to avoid this issue
}
bannedWords.forEach(function(item,index){
if (text.includes(item)){
parent.sendMessage(nick + " > You're not allowed to use that type of language.");
parent.sendMessage("/timeout " + nick + " 10");
}
});
commands.forEach(function(item, index){
var splitData = text.split(' ');
if (splitData[0] == item.getExecutor()) {
//running this command
var response = item.getResponse();
response = response.replace("%user%", nick);
response = response.replace("%bot_username%", config.botName);
parent.sendMessage(response);
}
});
});
}
Bot Creation(This is being called before the connection)
this.createBot = function(channel) {
currentChannel = channel;
var irc = require('irc');
botInstance = new irc.Client(config.server, config.botName, {
channels: [currentChannel + " " + config.oAuth],
userName: config.botName,
password: config.oAuth
});
}
Bot Sending Messages
this.sendMessage = function(msg){
if(botInstance != null) {
botInstance.say(currentChannel, msg);
lastMessage = msg;
}

RecordRTC upload video to node js server

I am using RecordRTC from recording webrtc meeting. After implementing recording, when I test this application if both client are on the same system then its working fine. When I test this application on different system it isn't working fine and meeting is not recorded.
Here this is my code from stop recording client side.
recordRTC.stopRecording(function (videoURL) {
console.log('recordRTC.stopRecording Function inside');
SelectedFile = recordRTC.getBlob();
$('#uploadForm').append('#attachmentFileId', recordRTC.getBlob());
StartUpload();
});
var FReader;
var Name = "Meeting" + "_" + Date.now() + ".webm";
function StartUpload()
{
FReader = new FileReader();
FReader.onload = function (evnt)
{
socket.emit('Upload', { 'Name': Name, Data: evnt.target.result });
}
socket.emit('Start', { 'Name': Name, 'Size': SelectedFile.size });
}
socket.on('MoreData', function (data)
{
var Place = data['Place'] * 524288; //The Next Blocks Starting Position
var NewFile; //The Variable that will hold the new Block of Data
if (SelectedFile.webkitSlice)
NewFile = SelectedFile.webkitSlice(Place, Place + Math.min(524288, (SelectedFile.size - Place)));
else
NewFile = SelectedFile.slice(Place, Place + Math.min(524288, (SelectedFile.size - Place)));
FReader.readAsBinaryString(NewFile);
});
Server Side Code
I get this from here.
socket.on('Start', function (data) { //data contains the variables that we passed through in the html file
var Name = data['Name'];
Files[Name] = { //Create a new Entry in The Files Variable
FileSize : data['Size'],
Data : "",
Downloaded : 0
}
var Place = 0;
try{
var Stat = fs.statSync('Temp/' + Name);
if(Stat.isFile())
{
Files[Name]['Downloaded'] = Stat.size;
Place = Stat.size / 524288;
}
}
catch(er){} //It's a New File
fs.open("Temp/" + Name, 'a', 0755, function(err, fd){
if(err)
{
console.log(err);
}
else
{
Files[Name]['Handler'] = fd; //We store the file handler so we can write to it later
socket.emit('MoreData', { 'Place' : Place, Percent : 0 });
}
});
});
socket.on('Upload', function (data){
var Name = data['Name'];
Files[Name]['Downloaded'] += data['Data'].length;
Files[Name]['Data'] += data['Data'];
if(Files[Name]['Downloaded'] == Files[Name]['FileSize']) //If File is Fully Uploaded
{
fs.write(Files[Name]['Handler'], Files[Name]['Data'], null, 'Binary', function(err, Writen){
var input = fs.createReadStream("Temp/" + Name);
var output = fs.createWriteStream("Video/" + Name);
//util.pump(readableStream, writableStream, [callback])
//Deprecated: Use readableStream.pipe(writableStream)
input.pipe(output);
input.on("end", function() {
console.log("end");
fs.unlink("Temp/" + Name, function ()
{ //This Deletes The Temporary File
console.log("unlink this file:",Name );
//socket.emit('Done', {'Image' : 'Video/' + Name + '.jpg'});
});
});
});
}
else if(Files[Name]['Data'].length > 10485760){ //If the Data Buffer reaches 10MB
fs.write(Files[Name]['Handler'], Files[Name]['Data'], null, 'Binary', function(err, Writen){
Files[Name]['Data'] = ""; //Reset The Buffer
var Place = Files[Name]['Downloaded'] / 524288;
var Percent = (Files[Name]['Downloaded'] / Files[Name]['FileSize']) * 100;
socket.emit('MoreData', { 'Place' : Place, 'Percent' : Percent});
});
}
else
{
var Place = Files[Name]['Downloaded'] / 524288;
var Percent = (Files[Name]['Downloaded'] / Files[Name]['FileSize']) * 100;
socket.emit('MoreData', { 'Place' : Place, 'Percent' : Percent});
}
});
If both clients are on same machine/system its working fine, but if both clients are on different system then meeting is not recorded.

How to make a node.js application keep listening after closing a socket?

I'm trying to set up a node.js application that could receive connections and still be listening to port 9001 once a socket is ended. How can I do that? Here is my current code (it doesn't close after the socket.end(), but it won't accept any other connections) :
var net = require('net');
var mySocket;
var server = net.createServer(function(socket) {
mySocket = socket;
mySocket.on("connect", onConnect);
mySocket.on("data", onData);
});
function onConnect() {
console.log("Connected");
}
function onData(command) {
if (command == "exit") {
console.log("Exiting");
mySocket.end();
}
}
console.log("Waiting for incoming connections");
server.listen(9001);
I tried to add another server.listen(9001); after the socket.end();, but I get a : Error: listen EADDRINUSE message.
Also, will that code be able to receive several connections coming from different addresses at the same time, and handle them separately?
This is the full code. When executed, node.js receives 4 commands from the Flash application, and works properly (except that the onConnect() function seems never to be called), and the "exit;" command closes the socket properly, yet if I reload the Flash application, it doesn't connect to the server
var net = require('net');
const PACKET_SEPARATOR = 59 // ;
var connection_ack = false;
var counter = 0;
var server = net.createServer(function(socket) {
function onConnect() {
console.log("Connected to Flash");
}
function dataHandler(command) {
if (command[command.length - 1] != String.fromCharCode(PACKET_SEPARATOR) && connection_ack) {
console.log("SEP : " + PACKET_SEPARATOR + " - last : " + command[command.length - 1] + " - ack " + connection_ack);
console.log("CAUGHT EXCEPTION : WRONG PACKET FORMAT --- " + command + " --- " + command.length);
}
if (command == "exit;") {
console.log("Received exit request from " + socket.address().address + ":" + socket.address().port + " (" + socket.address().family + "). Ending connection...");
socket.end();
}
else if (command == "<policy-file-request/>\0") {
socket.write('<cross-domain-policy>\n<allow-access-from domain="*" to-ports="*" />\n</cross-domain-policy>\0', 'utf8');
console.log("Policy file sent to " + socket.address().address + ":" + socket.address().port);
player1.pxacceleration = 0;
player1.pyacceleration = 0;
connection_ack = true;
}
else {
console.log("Got data from " + socket.address().address + ":" + socket.address().port + " (" + socket.address().family + ")");
console.log("--> " + command);
counter++;
socket.write("Received " + counter + " commands;", 'utf8');
console.log("Sending : Received " + counter + " commands;");
}
}
function onData(d) {
var command = "";
for (i=0; i <= d.length - 1; i++) {
command += String.fromCharCode(d[i]);
if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
dataHandler(command);
command = "";
}
}
}
socket.on("connect", onConnect);
socket.on("data", onData);
});
console.log("Ready. Waiting for incoming connections");
server.listen(9001);
server.listen(80); //TODO : Remove?
As jfriend00 said, using mySocket as a global is not recommended. Try the below instead.
var server = net.createServer(function(socket) {
function onData(command) {
if (command == "exit") {
console.log("Exiting");
socket.end();
}
}
socket.on("connect", onConnect);
socket.on("data", onData);
});
...
This eliminates the need for the global in the first place. This should also allow multiple sockets and prevent the original error. I think. I'm new here, so I guess we will see.
EDIT
Alright. I've been interacting with your code via telnet. I've also read up on some of the documentation. First, the socket.on("connect", onConnect); listener should be moved(along with the onConnect function) into the global scope and changed to server.on("connection", onConnect);. The reason for this is that the socket event listener connect is a client side listener. We are working server side. The server side listener for new connections is connection and the server should be listening for it in the same way it is listening for connections on a particular port.
This part of your code should look like this now:
//more code up above here
....
function onData(d) {
var command = "";
for (i=0; i <= d.length - 1; i++) {
command += String.fromCharCode(d[i]);
if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
dataHandler(command);
command = "";
}
}
}
socket.on("data", onData);
});
function onConnect() {
console.log("Connected to Flash");
}
server.on("connection", onConnect);
....
//more code below here
However, the code would not recognize exit as a command via telnet. I was unable to figure this bit out. Since your question did not cover this problem it might just be me or you have it figured out.
EDIT 2
The code below keeps it local.
var server = net.createServer(function(socket) {
function onConnect() {
console.log("Connected to Flash");
socket.write("we're connected");
}
....
function onData(d) {
var command = "";
for (i=0; i <= d.length - 1; i++) {
command += String.fromCharCode(d[i]);
if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
dataHandler(command);
command = "";
}
}
}
onConnect();
socket.on("data", onData);
});

Resources