PeerJS: Other Peer Detected but Connection Not Open - javascript

I am using PeerJS to establish peer-to-peer connections. It seems that I have been able to establish a connection momentarily but I have been unable to send and receive data over the connection. Below is my code:
var peer;
var nbcc = [];
function updatePeerConnections(){
if (!id) return;
if (!peer) {
peer = new Peer(id,{key: '52hhtusf1t0rudi'});
peer.on('open', function(conn) {
console.log('new connection');
});
peer.on('connection', function(conn) {
conn.on('open', function(){
console.log('connected!');
conn.on('data', function(data){
let o = JSON.parse(data);
console.log('updating car ' + o.i);
updateCarMarker(o.id,o.lat,o.lng);
});
});
conn.on('error', function(err){
console.log(err);
});
console.log(conn.open+': remote peer detected: '+conn.peer);
conn.id = conn.peer;
nbcc[conn.peer] = conn;
});
peer.on('error', function(err){
console.log(err.type);
});
updateConnections();
} else {
updateConnections();
}
}
function updateConnections(){
for (cm of Object.values(carMarkers)){
if (cm.id!=id && !Object.keys(nbcc).includes(cm.id)){
console.log('connecting to '+cm.id)
nbcc[cm.id] = peer.connect(cm.id);
nbcc[cm.id].id = cm.id;
nbcc[cm.id].on('error', function(err){
console.log(err);
});
nbcc[cm.id].on('open', function(){
console.log('connected!');
nbcc[cm.id].on('data', function(data){
let o = JSON.parse(data);
console.log('updating car ' + o.i);
updateCarMarker(o.id,o.lat,o.lng);
});
});
}
}
}
On the browser console, it printed 'new connection' and then 'false: remote peer detected: 879874543958', where the id is the remote peer (another tab in the browser). It never printed 'connected!' nor any error message. What is wrong with the code?

I found the problem!
It is with this line:
peer = new Peer(id,{key: '52hhtusf1t0rudi'});
We must not set the optional parameter 'id' ourselves. Instead, we should receive it in peer.on('connection',function(id){...})
Duh. Why allow that parameter to be set when it musn't be set. That is confusing.

If this works in localhost but doesn't work over the internet then you are probably missing a STUN and a TURN server.
By default peer js uses the google global stun server but you will have to get a turn server for this to work in production.

Related

WebRTC more than one peer connection

I searched almost everywhere and can't seem to find any resource on this scenario for some reason. Any help would greatly be appreciated.
The problem is this:
I have 4 users. Lets say: A,B,C and D. I want to match them according to url. For example, if A and B connects to &room=1 and C and D connects to &room=2 I want to establish the connection between A and B pairs and C and D pairs.
Currently my code only establishes connection between A and B, and if one of the C or D users initiates the call, the connection between A and B gets disconnected and C cannot find D.
In order to solve this problem I tried to create an object like this:
{
room: 1,
peer: RTCPeerConnection
}
and store it in an array and get the peer connection according to room id and establish the connection based on RTCPeerConnection that is stored according to roomId. But that didn't work.
How would I go around fixing this without establishing a socket server that handles this communication?
I currently establish connections this way if it helps:
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true
})
.then(function (stream) {
localStream = stream;
localVideo.srcObject = localStream;
try {
conn = new RTCPeerConnection(servers);
} catch (err) {
console.log("Can't establish connection");
return;
}
localStream.getTracks().forEach(function (track) {
conn.addTrack(track, localStream);
});
conn.onaddstream = function (event) {
setTimeout(() => {
callButton.click();
}, 2000);
remoteVideo.srcObject = event.stream;
};
conn.onicecandidate = function (event) {
if (event.candidate) {
chat.server.iceCandidate(
JSON.stringify({ candidate: event.candidate })
);
}
};
})
.catch(function (err) {
console.log("Error", err);
});
And this is my failed solution:
var connections = JSON.parse(localStorage.getItem("connections")) || [];
var connection;
if (connections) {
connection = connections.find(function (conn) {
return conn.id = roomId;
})
}
if (!connection) {
conn = new RTCPeerConnection(servers);
var data = {
id: roomId,
peer: conn
}
localStorage.removeItem("connections");
localStorage.setItem("connections", JSON.stringify(connections));
} else {
conn = JSON.parse(connection.peer);
conn.__proto__ = new RTCPeerConnection();
}
This fails because of course you can't store proto of an object in localStorage (RTCPeerConnection). When I stringify/parse it peer attribute comes as an empty object. If I try a global variable, instead of localStorage, it always comes empty. I'd very appreciate any tip about this issue.
It's like your messing up with the localStorage variable, for testing purpose and avoid the signaling server implementation, I advice to use the serverless-webrtc or an updated by jameshfisher
With this you can create the rooms (separate the clients) and show you a sdp message to copy and paste to the other client (without localStorage) to make the peer connection.
This will be better to test between browsers firefox <-> chrome, safari, etc.

Nodejs and WebSockets Failed to construct 'WebSocket': The subprotocol '[object Object]' is invalid

So my main webpage example.com is run through cloudflare and has a edge certificate from Origin -> CF Edge (origin cert) and an edge certificate CF Edge -> Client. I'm bypassing this for my websocket by using a subdomain, dt.example.com which uses cloudflare although using this link resolves the origin server address rather than the cloudflare edge server address (which i've found solves some issues for me, or maybe it's counterproductive to use this method?). Anyway, I am using a free ssl certificate for secure websockets -
'use strict';
var https = require('https');
var fs= require('fs');
var express = require('express');
var WebSocket = require('ws');
var server = https.createServer({
cert: fs.readFileSync('../ssl/wss/new/certificate.crt'),
key: fs.readFileSync('../ssl/wss/new/private.pem'),
ca: fs.readFileSync('../ssl/wss/new/ca_bundle.crt')
});
const wss = new WebSocket.Server({server});
wss.on('connection', function connection (ws) {
ws.on('message', function message (msg) {
console.log(msg);
});
});
server.listen(58443, function listening () {
const ws = new WebSocket('wss://dt.example.com:58443', {
rejectUnauthorized: false
});
ws.on('open', function open () {
ws.send('Workin baby');
});
});
-and using a websocket client plugin for chrome allows me to connect to the socket, however i cannot on example.com/webpage where the follow code is:
var ws = new window.WebSocket('wss://dt.example.com:58443/', {
rejectUnauthorized: false
});
ws.on('open', function open () {
ws.send('What\'s crackin?');
});
Although in browser (Chrome) when the client script executes it exits with the following error Uncaught DOMException: Failed to construct 'WebSocket': The subprotocol '[object Object]' is invalid. (on line 1)
I managed to solve this by stumbling across something intriguing in a post elswhere.
Essentially I just moved the rejectUnauthorized into the server code and then retried running on the client and it connected to the server :)
So there are two ways of doing this i'll list out both of them ,for more information you can visit https://www.npmjs.com/package/websocket
Using W3CWebSocket
var ws= require('websocket').w3cwebsocket;
var client = new W3CWebSocket('wss://dt.example.com:58443/'{
rejectUnauthorized: false
}, 'echo-protocol');
client.onerror = function() {
console.log('Connection Error');
};C
client.onopen = function open () {
ws.send('What\'s crackin mate?');
};
client.onclose = function() {
console.log('echo-protocol Client Closed');
};
client.onmessage = function(e) {
if (typeof e.data === 'string') {
console.log("Received: '" + e.data + "'");
}
};
Using a normal websocket client
var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();
client.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
});
client.on('connect', function(connection) {
console.log('WebSocket Client Connected');
connection.on('error', function(error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function() {
console.log('echo-protocol Connection Closed');
});
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log("Received: '" + message.utf8Data + "'");
}
});
});
client.connect('ws://localhost:8080/', 'echo-protocol');
You can solve this problem by adding corresponding protocol value in front side to the response header in back-end side with key = "Sec-WebSocket-Protocol".
In your case , you should add a HTTP header with key "Sec-WebSocket-Protocol" and with value "Chat-1.0"

Nodejs lookup of known bluetooth device

Is it possible to perform a lookup of a Bluetooth device given its address in a Nodejs script?
There are a few packages out there, the main one being Noble. However, they all focus around scanning, and not looking up a known address (as far as i can tell anyway!).
What i want to achieve, is to look up a known address, to see if the device can be found.
Much like PyBluez does for Python:
bluetooth.lookup_name('CC:20:E8:8F:3A:1D', timeout=5)
In Python, this can find the device even if it is undiscoverable, unlike a typical inquiry scan would.
I had this same problem and just found the btwatch lib, but it isn't working for me on the latest raspbian. But the source is just calling l2ping and looking for a string that I'm guessing no longer prints on success, so the modified code below works instead, similar to the lookup_name method, once you have l2ping installed (I think npm bluetooth or pybluez has it)
var Spawn = require('child_process').spawn;
function detectMacAddress(macAddress, callback)
{
//var macAddress = '72:44:56:05:79:A0';
var ls = Spawn('l2ping', ['-c', '1', '-t', '5', macAddress]);
ls.stdout.on('data', function (data) {
console.log("Found device in Range! " + macAddress);
callback(true);
});
ls.on('close', function () {
console.log("Could not find: " + macAddress);
callback(false);
});
}
Or, a synchronous way,
var execSync = require('child_process').execSync;
function detectMacAddressSync(macAddress)
{
var cmd = 'l2ping -c 1 -t 5 ' + macAddress;
try
{
var output = execSync(cmd );
console.log("output : "+ output );
return true;
}
catch(e)
{
console.log("caught: " + e);
return false;
}
}
As far as I have understood the problem you want to connect to the device using address. Then, I would suggest using node-bluetooth-serial-port.
var btSerial = new (require('bluetooth-serialport')).BluetoothSerialPort();
btSerial.on('found', function(address, name) {
btSerial.findSerialPortChannel(address, function(channel) {
btSerial.connect(address, channel, function() {
console.log('connected');
btSerial.write(new Buffer('my data', 'utf-8'), function(err, bytesWritten) {
if (err) console.log(err);
});
btSerial.on('data', function(buffer) {
console.log(buffer.toString('utf-8'));
});
}, function () {
console.log('cannot connect');
});
// close the connection when you're ready
btSerial.close();
}, function() {
console.log('found nothing');
});
});
BluetoothSerialPort.findSerialPortChannel(address, callback[, errorCallback])
Checks if a device has a serial port service running and if it is found it passes the channel id to use for the RFCOMM connection.
callback(channel) - called when finished looking for a serial port on the device.
errorCallback - called the search finished but no serial port channel was found on the device. Connects to a remote bluetooth device.
bluetoothAddress - the address of the remote Bluetooth device.
channel - the channel to connect to.
[successCallback] - called when a connection has been established.
[errorCallback(err)] - called when the connection attempt results in an error. The parameter is an Error object.

fail to connect localhost:8081 using node.js

I have opened the server.js and the address:http://localhost:8081 on my browser. But then a text "Upgrade Required" appeared at the top left conern of the website.
What is the problem of that? What else do I need to upgrade?
Here is the server.js:
var serialport = require('serialport');
var WebSocketServer = require('ws').Server;
var SERVER_PORT = 8081;
var wss = new WebSocketServer({
port: SERVER_PORT
});
var connections = new Array;
SerialPort = serialport.SerialPort,
portName = process.argv[2],
serialOptions = {
baudRate: 9600,
parser: serialport.parsers.readline('\n')
};
if (typeof portName === "undefined") {
console.log("You need to specify the serial port when you launch this script, like so:\n");
console.log(" node wsServer.js <portname>");
console.log("\n Fill in the name of your serial port in place of <portname> \n");
process.exit(1);
}
var myPort = new SerialPort(portName, serialOptions);
myPort.on('open', showPortOpen);
myPort.on('data', sendSerialData);
myPort.on('close', showPortClose);
myPort.on('error', showError);
function showPortOpen() {
console.log('port open. Data rate: ' + myPort.options.baudRate);
}
function sendSerialData(data) {
if (connections.length > 0) {
broadcast(data);
}
}
function showPortClose() {
console.log('port closed.');
}
function showError(error) {
console.log('Serial port error: ' + error);
}
function sendToSerial(data) {
console.log("sending to serial: " + data);
myPort.write(data);
}
wss.on('connection', handleConnection);
function handleConnection(client) {
console.log("New Connection");
connections.push(client);
client.on('message', sendToSerial);
client.on('close', function () {
console.log("connection closed");
var position = connections.indexOf(client);
connections.splice(position, 1);
});
}
function broadcast(data) {
for (c in connections) {
connections[c].send(data);
}
}
OK, websockets...
The "upgrade required" status marks the start of a websocket handshake. Normally your client sends this first to the WS server. The server answers in a pretty similar manner (details here : https://www.rfc-editor.org/rfc/rfc6455 ), and then proceed to pipe the actual data.
Here, you're opening a connection from your client as regular http, sending a simple GET. What you see on the screen is the server dumbly proceeding with an already corrupted handshake.
That's not how you open a WS client side connection. You don't usually open WS pages from the browser. It ought to be opened from a JavaScript call, such as new WebSocket(uri). So what you want is a regular http server on another port, that serves a page containing the necessary Javascript to open the actual WS connection and do something useful with its data. You'll find a clean example here : http://www.websocket.org/echo.html

Duplicate Events Socket.io and Node.js over STOMP

I need some help about my node.js+socket.io implementation.
This service expose a server that connects to an ActiveMQ broker over the STOMP protocol, using the stomp-js node.js module to receive events; that then are displayed in a web front end through websockets using socket.io.
So, everything was fine until I started use the Filters feature of ActiveMQ, but this was not the failure point because of my and my team researching, we found the way to ensure the implementation was fine, the problem comes with the connections: So here's the thing, I receive the filters to subscribe, I successfully subscribe to but when I receive a new set of filters is when comes the duplicated, triplicated and more and more messages depending the number of times that I subscribe-unsubscribe to.
So making some debug, I cannot see what's the problem but I'm almost sure that is some bad implementation of the callbacks or the program flow, I'll attach my code to read your comments about it.
Thanks a lot!
var sys = require('util');
var stomp = require('stomp');
var io = require('socket.io').listen(3000);
var socket = io.sockets.on('connection', function (socket) {
var stomp_args = {
port: 61616,
host: 'IP.ADDRESS',
debug: true,
};
var headers;
var client = new stomp.Stomp(stomp_args);
var setFilters = false;
socket.on('filtros', function (message) {
console.log('DEBUG: Getting filters');
if(setFilters){
client.unsubscribe(headers);
}
else{
client.connect();
}
var selector = '';
headers = '';
for(var attributename in message){
console.log(attributename+" : " + message[attributename]);
if(message[attributename] != ''){
selector += ' ' + attributename + '=\'' + message[attributename] + '\' AND ';
}
}
selector = selector.substring(0, selector.length - 4)
console.log('DEBUG: Selector String: ' + selector);
headers = {
destination: '/topic/virtualtopic',
ack: 'client',
selector: selector
};
if(setFilters)
client.subscribe(headers);
client.on('connected', function() {
client.subscribe(headers);
console.log('DEBUG: Client Connected');
setFilters = true;
});
});
var bufferMessage;
client.on('message', function(message) {
console.log("Got message: " + message.headers['message-id']);
var jsonMessage = JSON.parse(message.body);
if(bufferMessage === jsonMessage){
console.log('DEBUG: recibo un mensaje repetido');
return 0;
}
else{
console.log('DEBUG: Cool');
socket.emit('eventoCajero', jsonMessage);
}
client.ack(message.headers['message-id']);
bufferMessage = jsonMessage;
});
socket.on('disconnect', function(){
console.log('DEBUG: Client disconnected');
if(setFilters){
console.log('DEBUG: Consumer disconnected');
client.disconnect();
}
});
client.on('error', function(error_frame) {
console.log(error_frame.body);
});
});
Looking in the Socket.IO documentation, I've found that this is a known issue (I think critical known issue) and they have not fixed it yet. So, to correct this is necessary to reconnect to the socket in the client side to avoid duplicate messages, using:
socket.socket.reconnect();
function to force reconnection explicitly.

Categories