Socket.io fs.readFileSync for many connections at same time - node.js

This is not really a question, but I wonder to know if what I did is correct because its working!
So, lets to the question, I`m monitoring many interfaces (PPPoE clients) at same to know its traffic reading the statistics from linux.
I`m using npm packages: express, socket.io and socket.io-stream.
Client:
var sessionsAccel = $('table.accel').DataTable([]);
sessionsAccel.on('preDraw', function() {
$('.interfaceAccel').each(function(i) {
var t = $(this).data();
sockets['socket' + t.id].disconnect();
delete speeds['tx_bytes' + t.id];
delete speeds['rx_bytes' + t.id];
});
})
.on('draw', function() {
$('.interfaceAccel').each(function(i) {
var t = $(this).data();
sockets['socket' + t.id] = io.connect('http://172.16.101.2:3000/status', {
query: 'interface=' + t.interface,
'forceNew': true
});
sockets['socket' + t.id].on("connect", function() {
ss(sockets['socket' + t.id]).on('sendStatus', function(stream, data) {
if (typeof speeds['tx_bytes' + t.id] != 'undefined') {
var speedtx = (data.tx_bytes - speeds['tx_bytes' + t.id]) * 8 / 1000;
var speedrx = (data.rx_bytes - speeds['rx_bytes' + t.id]) * 8 / 1000;
if (speedtx > 1000) {
speedtx = speedtx / 1000;
speedtx = speedtx.toFixed(2);
speedtx_info = speedtx + ' Mbps';
} else {
speedtx = speedtx.toFixed(2);
speedtx_info = speedtx + ' kbps';
}
if (speedrx > 1000) {
speedrx = speedrx / 1000;
speedrx = speedrx.toFixed(2);
speedrx_info = speedrx + ' Mbps';
} else {
speedrx = speedrx.toFixed(2);
speedrx_info = speedrx + ' kbps';
}
$('.tx_' + t.id).html(speedtx_info);
$('.rx_' + t.id).html(speedrx_info);
}
speeds['tx_bytes' + t.id] = data.tx_bytes;
speeds['rx_bytes' + t.id] = data.rx_bytes;
});
});
});
})
Server:
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
const ss = require('socket.io-stream');
const path = require('path');
const fs = require('fs');
function getIntInfo(interface) {
if(fs.existsSync('/sys/class/net/'+ interface +'/statistics/tx_bytes')) {
var tx_bytes = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/tx_bytes').toString();
var rx_bytes = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/rx_bytes').toString();
var tx_packets = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/tx_packets').toString();
var rx_packets = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/rx_packets').toString();
return {tx_bytes : tx_bytes, rx_bytes : rx_bytes, tx_packets: tx_packets, rx_packets: rx_packets};
}else
return false;
}
io.of('/status').on('connection', function(socket) {
var query = socket.handshake.query['interface'];
var timer = setInterval(function() {
var stream = ss.createStream();
var info = getIntInfo(query);
ss(socket).emit('sendStatus', stream, info);
}, 1000);
socket.on('disconnect', function(){
socket.disconnect(true);
//console.info('disconnected user (id=' + socket.id + ').');
});
})
http.listen(3000, function(){
console.log('listening on *:3000');
});
That's it, every row from Datatable (which is the interface) open a socket connection and retrieve the statistics.
My question is, this will mess up my server with many I/O reading these files?

Since you're doing this every second for every connected client, it seems like you should probably cache this data so it doesn't have to be read from the disk or sent over the wire when it hasn't changed to save both server load and bandwidth usage. But, the details of how to best do that depend upon knowledge about your particular application that you haven't included.
You can at least use asynchronous I/O like this:
const util = require('util');
const fs = require('fs');
const readFile = util.promisify(fs.readFile);
function getIntInfo(interface) {
function readInfo(name) {
return readFile('/sys/class/net/'+ interface +'/statistics/' + name).then(data => data.toString());
}
return Promise.all(
readFile('tx_bytes'),
readFile('rx_bytes'),
readFile('tx_packets'),
readFile('rx_packets')
).then(([tx_bytes, rx_bytes, tx_packets, rx_packets]) => {
return {tx_bytes, rx_bytes, tx_packets, rx_packets};
}).catch(err => {
console.log(err);
return false;
});
}
And, you have to stop the interval any time a client disconnects and change how it calls getIntInfo():
io.of('/status').on('connection', function(socket) {
var query = socket.handshake.query['interface'];
var timer = setInterval(function() {
getIntInfo(query).then(info => {
var stream = ss.createStream();
ss(socket).emit('sendStatus', stream, info);
});
}, 1000);
socket.on('disconnect', function(){
// stop the timer for this connection
clearInterval(timer);
});
});
Now that I think about it a bit more, you could improve scalability quite a bit by having just one interval timer that was reading the data and then sending that one set of data to all listening clients that had connected to the /status namespace. You would reduce the file reading from once per second for every client to just once per second for no matter how many clients.

Related

Create webrtc video, voice call and file transfer using node js step by step Q-A

If any one need to add information or edit some information they are welcome.
Hi,
First of all this questions main target is shear my experience to other developers who finding good tutorials about webrtc.i'm not going to explain about webrtc. In this i add scourse code that working webrtc Video, voice call and file transfer example tested by me.
I get webrtc information from https://webrtc.org/ and get nodejs
from https://nodejs.org/en/
Ok let get start
Is web rtc need ssl certificated?
If you doing experiment in you local PC server no need. but when you add the to live server Yes you need it.
How i get ssl certificate?
one of my friend help me to get that SSl. there plenty of tutorials for you read and watch
How i get turn and stun server?
if you go production level you need to setup those server , but for test your project you can get stun server and turn servers for free.
For Stun server - https://gist.github.com/zziuni/3741933
For Turn server - Use this link and create free one ( http://numb.viagenie.ca/ ).
I add my working code as a an answer below
This is Working code for webrtc with node js
This code and comment that in code not by me. They already there when i got the code. I cant find code original owner. but i thanks that developer.If some found that developer please edit this and add that developer link :)
var express = require('express');
var socket = require('socket.io');
var app = express();
var fs = require('fs');
var https = require('https');
// link your https certicate path
var options = {
key: fs.readFileSync('/../../etc/ssl/private/apache-selfsigned.key'),
cert: fs.readFileSync('/../../etc/ssl/certs/apache-selfsigned.crt')
};
var main = https.createServer(options, app);
var server = main.listen(8443, function() {
console.log('server up and running at %s port', 8443);
});
/*var server = app.listen(443, function () {
});*/
app.use(express.static('public'));
var io = socket(server);
/*************************/
/*** INTERESTING STUFF ***/
/*************************/
var channels = {};
var sockets = {};
/**
* Users will connect to the signaling server, after which they'll issue a "join"
* to join a particular channel. The signaling server keeps track of all sockets
* who are in a channel, and on join will send out 'addPeer' events to each pair
* of users in a channel. When clients receive the 'addPeer' even they'll begin
* setting up an RTCPeerConnection with one another. During this process they'll
* need to relay ICECandidate information to one another, as well as SessionDescription
* information. After all of that happens, they'll finally be able to complete
* the peer connection and will be streaming audio/video between eachother.
*/
io.on('connection', function (socket) {
var channel;
socket.channels = {};
sockets[socket.id] = socket;
console.log("[" + socket.id + "] connection accepted");
socket.on('disconnect', function () {
for (var channel in socket.channels) {
part(channel);
}
console.log("[" + socket.id + "] disconnected");
delete sockets[socket.id];
});
socket.on('join-room', function (config) {
if (config) {
channel = config.channel;
var userdata = config.userdata;
var userID = config.userdata.userID;
if (channel in socket.channels) {
console.log("[" + socket.id + "] ERROR: already joined ", channel);
return;
}
if (!(channel in channels)) {
channels[channel] = {};
}
for (id in channels[channel]) {
channels[channel][id].emit('addPeer-room', {'peer_id': socket.id, 'should_create_offer': false});
socket.emit('addPeer-room', {'peer_id': id, 'should_create_offer': true});
console.log("what is this id -> ", id);
}
console.log(config.userdata.name, ' joining room', config.channel);
socket.join(config.channel);
socket.broadcast.in(config.channel).emit('room-users', config);
channels[channel][socket.id] = socket;
socket.channels[channel] = channel;
}
});
function part(channel) {
console.log("[" + socket.id + "] part ");
if (!(channel in socket.channels)) {
console.log("[" + socket.id + "] ERROR: not in ", channel);
return;
}
delete socket.channels[channel];
delete channels[channel][socket.id];
for (id in channels[channel]) {
channels[channel][id].emit('removePeer', {'peer_id': socket.id});
socket.emit('removePeer', {'peer_id': id});
}
}
socket.on('part', part);
socket.on('relayICECandidate-room', function (config) {
var peer_id = config.peer_id;
var ice_candidate = config.ice_candidate;
console.log("[" + socket.id + "] relaying ICE candidate to [" + peer_id + "] ", ice_candidate);
if (peer_id in sockets) {
sockets[peer_id].emit('iceCandidate-room', {'peer_id': socket.id, 'ice_candidate': ice_candidate});
}
});
socket.on('relaySessionDescription-room', function (config) {
var peer_id = config.peer_id;
var session_description = config.session_description;
console.log("[" + socket.id + "] relaying session description to [" + peer_id + "] ", session_description);
if (peer_id in sockets) {
sockets[peer_id].emit('sessionDescription-room', {
'peer_id': socket.id,
'session_description': session_description
});
}
});
// this for file transfer
socket.on('file-send-room', function (file) {
console.log(file);
socket.to(channel).emit('file-out-room', file);
});
socket.on('file-send-room-result', function (file) {
console.log(file);
socket.to(channel).emit('file-out-room-result', file);
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
var fileInput = document.querySelector('input#fileInput');
var downloadAnchor = document.querySelector('a#download');
// this function use to get url parameters
var room = getParameterByName('room');
var userID = getParameterByName('userid');
var name = getParameterByName('name');
/** CONFIG **/
var SIGNALING_SERVER = "https://xxx.xx.xx.xxx:8443"; //your node server addres or IP adress
var USE_AUDIO = true;
var USE_VIDEO = true;
var MUTE_AUDIO_BY_DEFAULT = false;
/** You should probably use a different stun server doing commercial stuff **/
/** Also see: https://gist.github.com/zziuni/3741933 **/
var ICE_SERVERS = [
{urls: "stun:stun.l.google.com:19302"},{
urls: 'turn:numb.viagenie.ca:3478',
credential: '12344', //your password
username: 'your#email.com'
}
];
var socket = null;
/* our socket.io connection to our webserver */
var local_media_stream = null;
/* our own microphone / webcam */
var peers = {};
/* keep track of our peer connections, indexed by peer_id (aka socket.io id) */
var peer_media_elements = {};
/* keep track of our <video>/<audio> tags, indexed by peer_id */
$(document).ready(function (a) {
socket = io(SIGNALING_SERVER);
socket = io();
//----------------------------------------------------------------------->>>>> Files Send Start
const BYTES_PER_CHUNK = 1200;
var file;
var currentChunk;
var fileInput = $('input[type=file]');
var fileReader = new FileReader();
function readNextChunk() {
var start = BYTES_PER_CHUNK * currentChunk;
var end = Math.min(file.size, start + BYTES_PER_CHUNK);
fileReader.readAsArrayBuffer(file.slice(start, end));
}
fileReader.onload = function () {
socket.emit('file-send-room-result', fileReader.result);
//p2pConnection.send( fileReader.result );
currentChunk++;
if (BYTES_PER_CHUNK * currentChunk < file.size) {
readNextChunk();
}
};
fileInput.on('change', function () {
file = fileInput[0].files[0];
currentChunk = 0;
// send some metadata about our file
// to the receiver
socket.emit('file-send-room', JSON.stringify({
fileName: file.name,
fileSize: file.size
}));
readNextChunk();
});
var incomingFileInfo;
var incomingFileData;
var bytesReceived;
var downloadInProgress = false;
socket.on('file-out-room', function (data) {
startDownload(data);
console.log(data);
});
socket.on('file-out-room-result', function (data) {
progressDownload(data);
console.log(data); });
function startDownload(data) {
incomingFileInfo = JSON.parse(data.toString());
incomingFileData = [];
bytesReceived = 0;
downloadInProgress = true;
console.log('incoming file <b>' + incomingFileInfo.fileName + '</b> of ' + incomingFileInfo.fileSize + ' bytes');
}
function progressDownload(data) {
bytesReceived += data.byteLength;
incomingFileData.push(data);
console.log('progress: ' + ((bytesReceived / incomingFileInfo.fileSize ) * 100).toFixed(2) + '%');
if (bytesReceived === incomingFileInfo.fileSize) {
endDownload();
}
}
function endDownload() {
downloadInProgress = false;
var blob = new Blob(incomingFileData);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var blob = new Blob(incomingFileData);
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = incomingFileInfo.fileName;
a.click();
window.URL.revokeObjectURL(url);
}
//==================================================================<<< Filse Send End
//------------------------ Funtion
function join_chat_channel(channel, userdata) {
socket.emit('join-room', {"channel": channel, "userdata": userdata});
}
socket.on('connect', function (userID) {
console.log("Connected to signaling server");
setup_local_media(function () {
/* once the user has given us access to their
* microphone/camcorder, join the channel and start peering up */
join_chat_channel(room, {'name': name, 'userID': userID});
});
});
socket.on('room-user', function (data) {
console.log(data);
$("#online-user").append('<tr><td>Name = ' + data.userdata.name + ' <br> User ID= ' + data.userdata.userID + '</td><td><button class="call" id="' + data.userdata.userID + '">Call</button></td></tr>');
});
$('body').on('click', '.call', function () {
var callerID = $(this).attr('id');
socket.emit('call', {"callToId": callerID, "callFromId": userID});
});
/**
* When we join a group, our signaling server will send out 'addPeer' events to each pair
* of users in the group (creating a fully-connected graph of users, ie if there are 6 people
* in the channel you will connect directly to the other 5, so there will be a total of 15
* connections in the network).
*/
socket.on('addPeer-room', function (config) {
console.log('Signaling server said to add peer:', config);
var peer_id = config.peer_id;
if (peer_id in peers) {
/* This could happen if the user joins multiple channels where the other peer is also in. */
console.log("Already connected to peer ", peer_id);
return;
}
var peer_connection = new RTCPeerConnection(
{"iceServers": ICE_SERVERS},
{"optional": [{"DtlsSrtpKeyAgreement": true}]} /* this will no longer be needed by chrome
* eventually (supposedly), but is necessary
* for now to get firefox to talk to chrome */
);
peers[peer_id] = peer_connection;
peer_connection.onicecandidate = function (event) {
if (event.candidate) {
socket.emit('relayICECandidate-room', {
'peer_id': peer_id,
'ice_candidate': {
'sdpMLineIndex': event.candidate.sdpMLineIndex,
'candidate': event.candidate.candidate
}
});
}
}
peer_connection.onaddstream = function (event) {
console.log("onAddStream", event);
var remote_media = USE_VIDEO ? $("<video>") : $("<audio>");
remote_media.attr("autoplay", "autoplay");
if (MUTE_AUDIO_BY_DEFAULT) {
remote_media.attr("muted", "true");
}
remote_media.attr("controls", "");
peer_media_elements[peer_id] = remote_media;
$('body').append(remote_media);
attachMediaStream(remote_media[0], event.stream);
}
/* Add our local stream */
peer_connection.addStream(local_media_stream);
/* Only one side of the peer connection should create the
* offer, the signaling server picks one to be the offerer.
* The other user will get a 'sessionDescription' event and will
* create an offer, then send back an answer 'sessionDescription' to us
*/
if (config.should_create_offer) {
console.log("Creating RTC offer to ", peer_id);
peer_connection.createOffer(
function (local_description) {
console.log("Local offer description is: ", local_description);
peer_connection.setLocalDescription(local_description,
function () {
socket.emit('relaySessionDescription-room',
{'peer_id': peer_id, 'session_description': local_description});
console.log("Offer setLocalDescription succeeded");
},
function () {
Alert("Offer setLocalDescription failed!");
}
);
},
function (error) {
console.log("Error sending offer: ", error);
});
}
});
/**
* Peers exchange session descriptions which contains information
* about their audio / video settings and that sort of stuff. First
* the 'offerer' sends a description to the 'answerer' (with type
* "offer"), then the answerer sends one back (with type "answer").
*/
socket.on('sessionDescription-room', function (config) {
console.log('Remote description received: ', config);
var peer_id = config.peer_id;
var peer = peers[peer_id];
var remote_description = config.session_description;
console.log(config.session_description);
var desc = new RTCSessionDescription(remote_description);
var stuff = peer.setRemoteDescription(desc,
function () {
console.log("setRemoteDescription succeeded");
if (remote_description.type == "offer") {
console.log("Creating answer");
peer.createAnswer(
function (local_description) {
console.log("Answer description is: ", local_description);
peer.setLocalDescription(local_description,
function () {
socket.emit('relaySessionDescription-room',
{'peer_id': peer_id, 'session_description': local_description});
console.log("Answer setLocalDescription succeeded");
},
function () {
Alert("Answer setLocalDescription failed!");
}
);
},
function (error) {
console.log("Error creating answer: ", error);
console.log(peer);
});
}
},
function (error) {
console.log("setRemoteDescription error: ", error);
}
);
console.log("Description Object: ", desc);
});
/**
* The offerer will send a number of ICE Candidate blobs to the answerer so they
* can begin trying to find the best path to one another on the net.
*/
socket.on('iceCandidate-room', function (config) {
var peer = peers[config.peer_id];
var ice_candidate = config.ice_candidate;
peer.addIceCandidate(new RTCIceCandidate(ice_candidate));
});
/**
* When a user leaves a channel (or is disconnected from the
* signaling server) everyone will recieve a 'removePeer' message
* telling them to trash the media channels they have open for those
* that peer. If it was this client that left a channel, they'll also
* receive the removePeers. If this client was disconnected, they
* wont receive removePeers, but rather the
* signaling_socket.on('disconnect') code will kick in and tear down
* all the peer sessions.
*/
socket.on('removePeer-room', function (config) {
console.log('Signaling server said to remove peer:', config);
var peer_id = config.peer_id;
if (peer_id in peer_media_elements) {
peer_media_elements[peer_id].remove();
}
if (peer_id in peers) {
peers[peer_id].close();
}
delete peers[peer_id];
delete peer_media_elements[config.peer_id];
});
});
function setup_local_media(callback, errorback) {
if (local_media_stream != null) { /* ie, if we've already been initialized */
if (callback) callback();
return;
}
/* Ask user for permission to use the computers microphone and/or camera,
* attach it to an <audio> or <video> tag if they give us access. */
console.log("Requesting access to local audio / video inputs");
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
attachMediaStream = function (element, stream) {
console.log('DEPRECATED, attachMediaStream will soon be removed.');
element.srcObject = stream;
};
navigator.getUserMedia({"audio": USE_AUDIO, "video": USE_VIDEO},
function (stream) { /* user accepted access to a/v */
console.log("Access granted to audio/video");
local_media_stream = stream;
var local_media = USE_VIDEO ? $("<video>") : $("<audio>");
local_media.attr("autoplay", "autoplay");
local_media.attr("muted", "true");
/* always mute ourselves by default */
local_media.attr("controls", "");
$('body').append(local_media);
attachMediaStream(local_media[0], stream);
if (callback) callback();
},
function () { /* user denied access to a/v */
console.log("Access denied for audio/video");
alert("You chose not to provide access to the camera/microphone, demo will not work.");
if (errorback) errorback();
});
}
</script>
</head>
<body>
<form id="fileInfo">
<input type="file" id="fileInput" name="files"/>
</form>
<a id="download"></a>
</body>
</html>

node.js server not always clearing data from previous run

I'm brand new to node.js (or javascript in general) and not sure what's going on here. Sometimes when I run my node.js server, right when it starts up it begins printing data from the last time it ran. Is there something that could be keeping everything from resetting on a new run? I have arduino XBee nodes connecting to this server. Here's my node.js code:
var SerialPort = require("serialport");
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var ON_DEATH = require('death');
// Set up serial port
var portName = process.argv[2],
portConfig = {
baudRate: 9600,
parser: SerialPort.parsers.readline("\n")
};
var sp = new SerialPort(portName, portConfig); // got rid of deprecation issue with sp4
// Respond with file when a GET request is made to the homepage: app.METHOD(PATH, HANDLER) '/'=homepage
app.get('/', function(req, res){
res.sendfile('index.html');
});
// Listen on the connection event for incoming sockets, and log it to the console.
io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
});
socket.on('chat message', function(msg){
io.emit('chat message', msg);
sp.write(msg + "\n");
});
});
// Make the http server listen on port 3000
http.listen(3000, function(){
console.log('listening on *:3000');
});
/////////////////////////////////////////////////////////////////////////////////////////////////
sp.on("open", function (err) {
if (err)
return console.log('Error opening port: ', err.message);
console.log('open');
// INFO VARIABLES
//var nodeCount = 0;
var pendingNodes = [];
var connectedNodes = [];
var buffer0;
var nodeInfo;
// Cleanup when termination signals are sent to process
ON_DEATH(function(signal, err) {
var death_msg = "Q";
sp.write(death_msg);
sp.close();
// zero out all variables
pendingNodes = [];
connectedNodes = [];
buffer0 = [];
nodeInfo = [];
console.log("\n\nSending reset signal to nodes.\n\n")
sp.flush(function(err,results){});
process.exit();
})
// listen for data, grab time, delimit
sp.on('data', function(data) {
var time = new Date();
buffer0 = data.split('\n'); // array of data till newline
// Split again into either "#ID" into [#ID] (if new broadcast), or "#ID Data" into [#ID, Data] (preconnected node)
nodeInfo = buffer0[0].split(' ');
//console.log(" nodeInfo: " + nodeInfo);
// DEBUGGING PRINT -- DELETE LATER
//console.log(" pendingNodes: " + pendingNodes + " connectedNodes: " + connectedNodes);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Receiving ID or [ID, Data] -- Testing all possible cases
// if first char
if (nodeInfo[0][0] == "#") { // could check up here for && no temp data too
// Brand new node (ID not in pendingNodes or connectedNodes)
if ((pendingNodes.indexOf(nodeInfo[0]) == -1) && (connectedNodes.indexOf(nodeInfo[0]) == -1)) {
console.log("Brand new node: " + nodeInfo[0])
pendingNodes.push(nodeInfo[0]);
}
// Pending node (ID in pendingNodes, but not in connectedNodes)
else if ((pendingNodes.indexOf(nodeInfo[0]) != -1) && ((connectedNodes.indexOf(nodeInfo[0]) == -1))) {
console.log(" Pending node: " + nodeInfo[0])
// send back ID to confirm handshake
sp.write(nodeInfo[0]);
// Remove from pendingNodes
var index = pendingNodes.indexOf(nodeInfo[0]);
if (index > -1) {
pendingNodes.splice(index, 1);
}
// Add to connectedNodes
//var
connectedNodes.push(nodeInfo[0]);
}
// Connected node (ID in connectedNodes, but not in pendingNodes)
else if ((pendingNodes.indexOf(nodeInfo[0]) == -1) && (connectedNodes.indexOf(nodeInfo[0]) != -1)) {
console.log(" Connected node: " + nodeInfo[0] + " " + nodeInfo[1]);
// Disconnect nodes with undefined temperatures to force restart
if (typeof nodeInfo[1] == 'undefined') {
console.log("Undefined data for node: " + nodeInfo[0] + ". Dropping connection to this node.");
var index = connectedNodes.indexOf(nodeInfo[0]);
if (index > -1) {
connectedNodes.splice(index, 1);
}
}
//var t = time.getTime();
// FIRST: fix bug -- sometimes temp showing as undefined
// Then:
// Update data properly
// Average data
// add 3rd element to nodes for time stamp, check that all timestamps are recent periodically
// Detect drop-offs and remove nodes
}
// Error (ID in both pendingNodes and connectedNodes [should not happen])
else {
console.log("Error: node exists in both pending and connected.")
}
}
else if (nodeInfo[0][0] != "#") {
// FOR DEBUGGING PURPOSES, DELETE LATER
console.log("Error 2: incoming data does not start with '#'.")
}
/* // placeholders for functionality to add
var CalcAverage = function() {
console.log("CalcAverage: * every 1 second(s) *");
}
setInterval(function(){ CalcAverage() },2000);
var CheckNodes = function() {
console.log("CheckNodes: * every 6 second(s) *");
}
setInterval(function(){ CheckNodes() },6000);
*/
}); // end data
}); // end open
And here's an example of old node data showing up somehow:
Some possibilities:
Old (or new data that you didn't know it sent) data from clients has been buffered somehow on the serial port, or socket.io auto-reconnects on the client browsers and starts sending data even though you didn't interact with the client browser web page.

Having Difficulties in Integrating a Simple Code Snippet into a Complex Existing Node.js Code

I am trying to add a new URL path (Node.js home page has given an example to do it.) to a piece of complex existing code (shown below). The existing code already has server configuration code but the code looks very different from the "Building a Node.js Web Server" example that is showing in the Node.js home page.
The new URL path is "/lens/v1/ping" that is sent from the browser window.
If that is the URL path received, I am supposed to send a response Status 200 back to the browser.
I am having difficulties to fit this new URL path and its associated code to the existing code (show below) and I am seeking help. Thank you very much.
/**
* Entry point for the RESTFul Service.
*/
var express = require('express')
var config = require('config');
var _ = require('underscore');
var bodyParser = require("vcommons").bodyParser;
// Export config, so that it can be used anywhere
module.exports.config = config;
var Log = require('vcommons').log;
var logger = Log.getLogger('SUBSCRIBE', config.log);
var http = require("http");
var https = require("https");
var fs = require("fs");
var cluster = require("cluster");
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('online', function (worker) {
logger.info('A worker with #' + worker.id);
});
cluster.on('listening', function (worker, address) {
logger.info('A worker is now connected to ' + address.address + ':' + address.port);
});
cluster.on('exit', function (worker, code, signal) {
logger.info('worker ' + worker.process.pid + ' died');
});
} else {
logger.info("Starting Subscription Application");
createApp();
}
// Create Express App
function createApp() {
var app = express();
app.configure(function () {
// enable web server logging; pipe those log messages through winston
var winstonStream = {
write : function (message, encoding) {
logger.trace(message);
}
}; // Log
app.use(bodyParser({}));
app.use(app.router);
if (config.debug) {
app.use(express.errorHandler({
showStack : true,
dumpExceptions : true
}));
}
});
// Include Router
var router = require('../lib/router')();
// Subscribe to changes by certain domain for a person
app.post('/lens/v1/:assigningAuthority/:identifier/*', router.submitRequest);
// Listen
if (!_.isUndefined(config.server) || !_.isUndefined(config.secureServer)) {
if (!_.isUndefined(config.server)) {
http.createServer(app).listen(config.server.port, config.server.host, function () {
logger.info("Subscribe server listening at http://" + config.server.host + ":"
+ config.server.port);
});
}
if (!_.isUndefined(config.secureServer)) {
https.createServer(fixOptions(config.secureServer.options), app).listen
(config.secureServer.port, config.secureServer.host, function () {
logger.info("Subscribe server listening at https://" + config.secureServer.host
+ ":" + config.secureServer.port);
});
}
} else {
logger.error("Configuration must contain a server or secureServer.");
process.exit();
}
}
function fixOptions(configOptions) {
var options = {};
if (!_.isUndefined(configOptions.key) && _.isString(configOptions.key)) {
options.key = fs.readFileSync(configOptions.key);
}
if (!_.isUndefined(configOptions.cert) && _.isString(configOptions.cert)) {
options.cert = fs.readFileSync(configOptions.cert);
}
if (!_.isUndefined(configOptions.pfx) && _.isString(configOptions.pfx)) {
options.pfx = fs.readFileSync(configOptions.pfx);
}
return options;
}
// Default exception handler
process.on('uncaughtException', function (err) {
logger.error('Caught exception: ' + err);
process.exit()
});
// Ctrl-C Shutdown
process.on('SIGINT', function () {
logger.info("Shutting down from SIGINT (Crtl-C)")
process.exit()
})
// Default exception handler
process.on('exit', function (err) {
logger.info('Exiting.. Error:', err);
});
A browser window executes a HTTP GET request. After the // Include Router call, that is where you would define your express GET function.
...
// Include Router
var router = require('../lib/router')();
//*********
//define your method here, as shown, or in your router file.
app.get('lens/v1/ping', function(req, res){
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end();
} );
//*********
// Subscribe to changes by certain domain for a person
app.post('/lens/v1/:assigningAuthority/:identifier/*', router.submitRequest);
...

WebRTC Video sharing app doesn't work

I have been trying to share a video stream between two clients over WebRTC for about a week now and I have no idea how to proceed any further. I'm frustrated and could really use some help from the more experienced. Please help me get this running.
I am using Websockets and NodeJS. I will post all of my code below:
Server Code ( on NodeJS )
"use strict";
/** Requires **/
var webSocketServer = require('websocket').server,
expr = require("express"),
xpress = expr(),
server = require('http').createServer(xpress);
// Configure express
xpress.configure(function() {
xpress.use(expr.static(__dirname + "/public"));
xpress.set("view options", {layout: false});
});
// Handle GET requests to root directory
xpress.get('/', function(req, res) {
res.sendfile(__dirname + '/public/index.html');
});
// WebSocket Server
var wsServer = new webSocketServer({
httpServer: server
});
// Set up the http server
server.listen(8000, function(err) {
if(!err) { console.log("Listening on port 8000"); }
});
var clients = [ ];
/** On connection established */
wsServer.on('request', function(request) {
// Accept connection - you should check 'request.origin' to make sure that client is connecting from your website
var connection = request.accept(null, request.origin);
var self = this;
// We need to know client index to remove them on 'close' event
var index = clients.push(connection) - 1;
// Event Listener for when Clients send a message to the Server
connection.on('message', function(message) {
var parsedMessage = JSON.parse(message.utf8Data);
if ( parsedMessage.kind == 'senderDescription' ) {
wsServer.broadcastUTF(JSON.stringify({ kind:'callersDescription', callerData: parsedMessage }));
}
});
});
Index.html loads and immediately runs VideoChatApp.js
function VideoChatApp() {
this.connection = null;
this.runConnection();
}
_p = VideoChatApp.prototype;
/** Initialize the connection and sets up the event listeners **/
_p.runConnection = function(){
// To allow event listeners to have access to the correct scope
var self = this;
// if user is running mozilla then use it's built-in WebSocket
window.WebSocket = window.WebSocket || window.MozWebSocket;
// if browser doesn't support WebSocket, just show some notification and exit
if (!window.WebSocket) { return; }
/** Where to make the connection **/
var host = location.origin.replace(/^http/, 'ws');
console.log(host);
this.connection = new WebSocket(host);
/** Once the connection is established **/
this.connection.onopen = function () {
console.log("Web Socket Connection Established");
self.onConnectionEstablished();
};
/** If there was a problem with the connection */
this.connection.onerror = function (error) {
console.log("ERROR with the connection *sadface*");
};
}; // end runConnection
_p.onConnectionEstablished = function() {
// My connection to the nodejs server
var websocketConnection = this.connection;
// Some local variables for use later
var mediaConstraints = {
optional: [],
mandatory: {
OfferToReceiveVideo: true
}
};
var offerer, answerer;
this.theLocalStream = null;
var amITheCaller = false;
var localVideoTag = document.getElementById('localVideoTag');
var remoteVideoTag = document.getElementById('remoteVideoTag');
window.RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
window.RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.URL = window.webkitURL || window.URL;
window.iceServers = {
iceServers: [{
url: 'stun:23.21.150.121'
}]
};
var callButton = document.getElementById("callButton");
callButton.onclick = callClicked;
function callClicked() {
amITheCaller = true;
setUpOffer();
}
offerer = new RTCPeerConnection(window.iceServers);
answerer = new RTCPeerConnection(window.iceServers);
/** Start Here - Set up my local stream **/
getUserMedia(function (stream) {
hookUpLocalStream(stream);
});
function getUserMedia(callback) {
navigator.getUserMedia({
video: true
}, callback, onerror);
function onerror(e) {
console.error(e);
}
}
function hookUpLocalStream(localStream) {
this.theLocalStream = localStream;
callButton.disabled = false;
localVideoTag.src = URL.createObjectURL(localStream);
localVideoTag.play();
};
/* When you click call, then we come here. Here I want to set up the offer and send it. */
function setUpOffer() {
var stream = theLocalStream;
offerer.addStream(stream);
offerer.onaddstream = function (event) {
console.log("onaddstream callback was called");
};
offerer.onicecandidate = function (event) {
if (!event || !event.candidate) return;
answerer.addIceCandidate(event.candidate);
};
offerer.createOffer(function (offer) {
offerer.setLocalDescription(offer);
console.log("------------------- What I am sending: -------------------------");
console.log(offer);
console.log(stream);
console.log("-----------------------------------------------------------------\n");
var jsonMsg = JSON.stringify( {kind:'senderDescription', streamInfo: offer, theStream: stream} );
websocketConnection.send( jsonMsg );
//answererPeer(offer, stream);
}, onSdpError, mediaConstraints);
}
/* Respond to a call */
function answererPeer(offer, stream) {
answerer.addStream(stream);
answerer.onaddstream = function (event) {
remoteVideoTag.src = URL.createObjectURL(event.stream);
remoteVideoTag.play();
};
answerer.onicecandidate = function (event) {
if (!event || !event.candidate) return;
offerer.addIceCandidate(event.candidate);
};
answerer.setRemoteDescription(offer, onSdpSucces, onSdpError);
answerer.createAnswer(function (answer) {
answerer.setLocalDescription(answer);
offerer.setRemoteDescription(answer, onSdpSucces, onSdpError);
}, onSdpError, mediaConstraints);
}
function onSdpError(e) {
console.error('onSdpError', e);
}
function onSdpSucces() {
console.log('onSdpSucces');
}
websocketConnection.onmessage = function (messageFromServer) {
console.log(" ------------------------ Message from server: -------------------- ");
var parsedMessage = JSON.parse(messageFromServer.data);
if(parsedMessage.callerData.kind = "senderDescription") {
console.log("Received a senderDescription");
console.log(parsedMessage.callerData.streamInfo);
console.log(parsedMessage.callerData.theStream);
console.log("-------------------------------------------------------------------\n");
answererPeer(parsedMessage.callerData.streamInfo, parsedMessage.callerData.theStream);
}
};
};// end onConnectionEstablished()
Finally, here are my errors:
I am not sure if this is still interesting for you, but I have some very good experience with WebRTC using PeerJS as a wrapper around it. It takes care of all the stuff you don't want to do (http://peerjs.com/). There is the client library as well as a very nice signaling server for nodejs (https://github.com/peers/peerjs-server). You can easy extend this server in your own node server.
This may not explain why your approach failed, but gets WebRTC running easily.
You can start with code that is already working and completely open. Check out easyrtc.com we have a client api, signalling server and working code. And if you have problems with that code ask us for help on Google Groups for easyrtc.

Increasing max_frame rate in amqp.js -- Hitting limits in buffer copy

I have a situation where I have about 50 listeners on 50 'direct' exchanges. The client and the server are in javascript (node.js) . It is using the node-amqp from postwait .
Things work fairly well at low frequency of messages. Once the message frequency increases ~ 5000 messages per minute then there is a buffer copy error being shown in amqp.js
From what I could trace the max_frame_size in amqp.js is fixed to 131072 .
I just tried to double the value from 128k to 256k . But doing so causes the node.js to silently fail without starting up. There is no error message. I am assuming that I also have to change the corresponding value (max_frame) in the rabbit.config file.
Do I have to do anything else to increase this value . Any other suggestions will also be appreciated.
I have attached the minimal code to simulate the error . Run the commands below in 2 windows to simulate the error
node engine-so-client.js -c 200 -p 12000
node server-so.js
File server-so.js
var util= require('util')
var amqp = require('amqp');
var express = require ('express')
function httpServer(exchange) {
console.log("In httpServer start %s",exchange.name);
var port;
app = express.createServer();
app.get('/message/:routingKey/:message',function(req,res) {
exchange.publish(req.params.routingKey,{'d' : req.params.message});
res.send('Published the message '+req.params.message+'\n');
});
app.get('/register/:socket/:routingKey',function(req,res) {
var queue1 = conn.queue('',
{autoDelete: false, durable: true, exclusive: true},
function() {
console.log("Queue1 Callback");
queue1.subscribe(
function(message) {
console.log("subscribe Callback for "+req.params.routingKey + " " + message.d);
});
console.log("Queue Callback Binding with "+req.params.routingKey);
queue1.bind(exchange.name,req.params.routingKey);
});
res.send('Started the socket at '+req.params.socket+'\n');
});
app.listen(3000);
app.use(express.logger());
console.log('Started server on port %s', app.address().port);
}
function setup() {
console.log("Setup");
var exchange = conn.exchange('cf2-demo',
{'type': 'direct', durable: false}, function() {
var queue = conn.queue('',
{autoDelete: false, durable: true, exclusive: true},
function() {
console.log("Queue Callback Binding with test key");
queue.bind(exchange.name,'testKey');
});
queue.on('queueBindOk',
function() { httpServer(exchange); });
});
console.log("Completed setup %s", exchange.name);
}
var conn = amqp.createConnection({host:'localhost',
login:'guest',
password:'guest'},
{defaultExchangeName: "cf2-demo"});
conn.on('ready',setup);
File engine-so-client.js
var program = require('commander.js');
var util = require('util');
var http = require('http');
program
.version('0.0.1')
.option('-h, --host <host>', 'Host running server', String,'localhost')
.option('-p, --port <port>', 'Port to open to connect messages on',Number,12000)
.option('-k, --key <key>,', 'Routing Key to be used',String,'key1')
.option('-c, --count <count>','Iteration count',Number,50)
.option('-m, --mesg <mesg>','Message prefix',String,'hello')
.option('-t, --timeout', 'Timeout in ms between message posts')
.parse(process.argv);
function setup(host,port,key,mesg) {
var client = http.createClient(3000, host);
var request = client.request('GET','/register/'+port+"/"+key);
request.end();
request.on('response', function(response) {
response.on('data', function(chunk) {
postMessage(host,port,key,mesg,1);
});
});
}
function postMessage(host,port,key,mesg,count) {
var timeNow = new Date().getTime();
var mesgNow = mesg+"-"+count+"-"+port;
console.log("Type: Sent Mesg, Message: %s, Time: %s",mesgNow,timeNow);
var client1 = http.createClient(3000, host);
var request1 = client1.request('GET','/message/'+key+"/"+mesgNow);
request1.end();
count++;
if (count <100) {
setTimeout( function() { postMessage(host,port,key,mesg,count); }, 1000 );
}
}
var port = program.port;
var host = program.host;
var key = program.key;
var mesg = program.mesg;
var count = program.count;
var keys = ['key1','key2','key3','key4','key5'];
var messages = ['hello','world','good','morning','bye'];
var start=port;
for (i=0; i<count; i++) {
var index = i%keys.length;
var socket = start + i;
setup(host,socket,keys[index],messages[index]);
}
Error attached
buffer.js:494
throw new Error('sourceEnd out of bounds');
^
Error: sourceEnd out of bounds
at Buffer.copy (buffer.js:494:11)
at frame (/home/hvram/programs/node_modules/node-amqp/amqp.js:170:10)
at header (/home/hvram/programs/node_modules/node-amqp/amqp.js:160:14)
at frameEnd (/home/hvram/programs/node_modules/node-amqp/amqp.js:205:16)
at frame (/home/hvram/programs/node_modules/node-amqp/amqp.js:172:14)
at header (/home/hvram/programs/node_modules/node-amqp/amqp.js:160:14)
at frameEnd (/home/hvram/programs/node_modules/node-amqp/amqp.js:205:16)
at frame (/home/hvram/programs/node_modules/node-amqp/amqp.js:172:14)
at header (/home/hvram/programs/node_modules/node-amqp/amqp.js:160:14)
at frameEnd (/home/hvram/programs/node_modules/node-amqp/amqp.js:205:16)

Resources