How to connect to a host with peerjs? - javascript

I'm trying to use peerjs to connect an host with a client. I have two files (one for the host, one for the client). The host will generate a peerId which the client is using to connect to him. It's basically the tutorial from here.
host.html
const peer = new Peer()
peer.on('open', () => {
console.log('ID: ' + peer.id)
})
peer.on('connection', (conn) => {
conn.on('data', (data) => {
// Will print 'hi!'
console.log(data)
})
conn.on('open', () => {
conn.send('hello!')
})
})
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
client.html
const peer = new Peer()
const conn = peer.connect('1781a113-d095-4be5-9969-b80d9c364f6b')
conn.on('open', () => {
conn.send('hi!')
})
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
The client is not connecting nor sending messages. I tried to use their example to connect to my host and this was working. I was able to send messages to the host. What is the issue with my client?

It's a little vague in the documentation, but if you don't wait on the open event, messages to the server will be queued. I'm not sure if there is additional configuration needed to enable queuing, but simply waiting on the open event should work in your case
const peer = new Peer()
peer.on('open', () => {
const conn = peer.connect('1781a113-d095-4be5-9969-b80d9c364f6b')
conn.on('open', () => {
conn.send('hi!')
})
})
Keep in mind that the peer id generated in your 'host' will change every time you refresh the browser, so you might want to pick your own id instead of getting a random one

Related

Why can WebRTC not reconnect after disconnecting?

I am building a web application using React where users can enter a group call. I have a NodeJS server that runs Socket.IO to manage the client events, and the users are connected through a peer-to-peer connection using simple-peers (WebRTC).
Everything is functional, from joining the call, seeing other users, and being able to leave. The call is "always open", similar to discord, and users can come and go as they please. However, if you leave and then try to rejoin the call without refreshing the page, the call breaks on all sides. The user leaving and rejoining gets the following error:
Error: cannot signal after peer is destroyed
For another user in the call, it logs the "user joined" event multiple times for the one user that tried to rejoin. Before it would add multiple peers as well, but I now make sure duplicates cannot exist.
However, to me, the strangest part is that when the user leaves, they send a call out to all other users in the room. The other users successfully destroy the peer connection and then remove the user from their peer array. The user who left on his turn also destroys each connection and resets the peer array to an empty array. So I'm very confused as to what PTP connection it is trying to re-establish.
const [roomSize, setRoomSize] = useState(0);
const socketRef = useRef();
const userVideo = useRef();
const peersRef = useRef([]);
const roomId = 'meeting_' + props.zoneId;
useEffect(async () => {
socketRef.current = io.connect(SERVER_URI, {
jsonp: false,
forceNew: true,
extraHeaders: {
"x-access-token": window.localStorage.getItem('accessToken'),
"zone-id": props.zoneId
}
});
}, []);
useEffect(async () => {
if (props.active) {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
height: window.innerHeight / 2,
width: window.innerWidth / 2
},
audio: true });
userVideo.current.srcObject = stream;
console.log(`%cJoined socket at ${SERVER_URI}, connected=${socketRef.current.connected}`, 'color: pink');
socketRef.current.emit("join room", roomId);
socketRef.current.on("all users", users => {
users.forEach(userID => {
const peer = createPeer(userID, socketRef.current.id, stream);
const peerObj = {
peerID: userID,
peer,
};
if (!peersRef.current.find(p => p.peerID === userID))
peersRef.current.push(peerObj);
});
setRoomSize(peersRef.current.length);
console.log(`%cNew Room Members: ${peersRef.current.length}; %o`, 'color: cyan', {peersRef: peersRef.current});
})
socketRef.current.on("user joined", payload => {
const peer = addPeer(payload.signal, payload.callerID, stream);
const peerObj = {
peerID: payload.callerID,
peer,
};
if (!peersRef.current.find(p => p.peerID === payload.callerID))
peersRef.current.push(peerObj);
setRoomSize(peersRef.current.length);
console.log(`%cSomeone Joined. Members: ${peersRef.current.length}; %o`, 'color: cyan', {peersRef: peersRef.current});
});
socketRef.current.on("receiving returned signal", payload => {
/** #type {Peer} */
const item = peersRef.current.find(p => p.peerID === payload.id);
item.peer.signal(payload.signal);
console.log("%creceiving return signal", 'color: lightgreen');
});
socketRef.current.on('user left', id => {
const peerObj = peersRef.current.find(p => p.peerID === id);
// console.log("user left", { peerObj });
if (peerObj)
peerObj.peer.destroy();
const peers = peersRef.current.filter(p => p.peerID !== id);
peersRef.current = peers;
setRoomSize(peersRef.current.length);
console.log(`%cSomeone Left. Members: ${peersRef.current.length}`, 'color: cyan');
});
} catch (err) {
console.trace(err);
}
}
else if (socketRef.current && socketRef.current.connected) {
socketRef.current.emit("leave room");
peersRef.current.forEach(peerObj => {
peerObj.peer.destroy();
});
peersRef.current = [];
setRoomSize(peersRef.current.length);
}
}, [props.active, peersRef.current]);
const createPeer = (userToSignal, callerID, stream) => {
const peer = new Peer({
initiator: true,
trickle: false,
stream,
});
peer.on("signal", signal => {
socketRef.current.emit("sending signal", { userToSignal, callerID, signal })
})
return peer;
}
const addPeer = (incomingSignal, callerID, stream) => {
const peer = new Peer({
initiator: false,
trickle: false,
stream,
})
peer.on("signal", signal => {
socketRef.current.emit("returning signal", { signal, callerID })
})
peer.signal(incomingSignal);
return peer;
}
Quick Edit: The above code is part of a React component that renders a video element for each peer.
When props.active becomes false is when the user leaves the call. This happens at the end of the second useEffect hook, where the client who left should have removed all their peer objects after destroying them. Why does this user receive the above error on a reconnect? And how do I keep this error from occurring?
Edit: I just noticed that when both users leave the call, and both try to rejoin without refreshing, the error does not occur. So something is different when removing a peer upon a user leaving compared to leaving yourself is my best guess.
TLDR; Put all refs you use in the useEffect body in the useEffect deps array.
I'd be sure to first check the useEffect deps array. It looks like socketRef is required in multiple places throughout that hook body, but it doesn't appear to be in the deps array. This can cause the hook to use less-than-current data.
It's also because of this that the socketRef ref object may never actually update, meaning, it may correctly remove the user from peers, as peerRefs is in the useEffect deps array, but the internal session (the room) may not recognize this; the room's internal representation of the user still exists.
Repeating myself, but just to make it clear, you mentioned:
So something is different when removing a peer upon a user leaving compared to leaving yourself is my best guess.
This is the same reason as listed above. The reason it happens when a peer leaves is because the peerRefs ref object IS in the useEffect deps array, so the effect you're describing is just 'perfect timing', if you will, since the applications state (all the refs) are correctly sync'd up with each other.

socket create multiple connection even when only one user connected

I'm new to Socket i try to receive image from server using socket-client-io . i can able to get image but on server side it shows multiple user created but i'm only seeing it in one tab but it shows like 10 users connected(like that)
Code:
const socket = io('ws://localhost:5000')
socket.on('connnection', () => {
console.log('connected to server');
})
socket.on('disconnect', () => {
console.log('Socket disconnecting');
})
useEffect(() => {
const handler = (message) => {
setImage(message.image);
console.log(message);
};
socket.on("send_image", handler);
return () => socket.off("send_image", handler); // assuming `.off` deregisters a callback
}, []);
it works fine and i can get images but it create multiple connection for single tab kindly guide me how to avoid this

websocket object is not connecting the socket in react native

Hy, I'm trying to connect WebSocket in react-native but it's not connected on the first attempt. I have two screen users and a chat screen. On the users screen when I click on the user it navigates to chat screen.
According to the documentation of WebSocket
In order to communicate using the WebSocket protocol, you need to create a WebSocket object; this will automatically attempt to open the connection to the server.
I created the object like this:
const client = new W3CWebSocket(
'ws://url:port/api/ws/chat/1/' + logID + '/',
);
and complete look like this
const client = new W3CWebSocket(
'ws://url:port/api/ws/chat/1/' + logID + '/',
);
useFocusEffect(
useCallback(() => {
getID()
client.onopen = () => {
console.log('WebSocket Client Connected');
};
client.onmessage=(message)=>{
const dataFromServer = JSON.parse(message.data);
console.log('got reply! ', dataFromServer);
if(dataFromServer){
setMessages(messages => [
...messages,
{msg: dataFromServer.type, sender: dataFromServer.sender},
]);
}
}
scrollHandler();
return () => {
scrollHandler();
client.close()
};
}, []),
);
But it does not connect to the WebSocket, but when I do some changes on my code or say when I save the code file after opening the chat screen, it is connected. That's means when I navigate the screens from user->chat it does not connect but on coming to the chat screen I go back to vscode and code of chat screen just press ctrl+s it connects the socket. I also try it inside the useEffect or useFocusEffect but it still behaves the same.
How I can solve this problem?

how to execute a function only once every X milliseconds?

im pretty new into javascript and node, currently working into a node.js app,
the app use express and mongoDB, the idea is listen to some third party services via webhook, websocket and mqtt and store all data into mongoDB.
but I have a litle problem, some of the third party apps send me data too often,
for example, the mqtt stream sends about 2 message every second, i need to store only one of those message every minute.
this is the way I instance mqtt into app.js
var mqttHandler = require('./mqtt/mqtt_handler'); //mqtt
var mqttClient = new mqttHandler(); //mqtt
mqttClient.connect(); //mqtt
this is my mqttHandler.js:
onst mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'mqtts://host';
this.username = 'foo'; // mqtt credentials if these are needed to connect
this.password = 'mypassqword';
this.port = 8083;
this.protocol = 'MQTTS';
this.client = 'bar'
}
connect() {
// Connect mqtt with credentials (in case of needed, otherwise we can omit 2nd param)
this.mqttClient = mqtt.connect(this.host, {password : this.password, username : this.username, port: this.port});
// Mqtt error calback
this.mqttClient.on('error', (err) => {
console.log(err);
this.mqttClient.end();
});
// Connection callback
this.mqttClient.on('connect', () => {
//console.log(`mqtt client connected`);
});
// mqtt subscriptions
this.mqttClient.subscribe('/the_subscription');
// When a message arrives, console.log it
this.mqttClient.on('message', function (topic, message) {
console.log(message.toString())
});
this.mqttClient.on('close', () => {
//console.log(`mqtt client disconnected`);
});
}
// Sends a mqtt message to topic: mytopic
sendMessage(message) {
this.mqttClient.publish('mytopic', message);
}
}
module.exports = MqttHandler;
i'veing reading about setInterval and setTimeout, but I can't figure out how to implement these to force a given function to only run once every X seconds (no mather how many times it is called)
could there be a similar / generic way to implement this feature for both, mqtt, webohooks and / or websocket?
I took this example about how to implement mqtt from a tutorial, its working perfect, as I said, im prettty new to javascript.
One naive approach using setInterval is to set a flag regularly and clear it once a message is posted. The ignore any other messages until the flag is set again by the interval function.
let readyToPost = false;
setInterval(function(){ readyToPost = true; }, 1000);
In your function:
function connect() {
if (!readyToPost) return; // do nothing
readyToPost = false;
// rest of your code
}
There is also a wrapper of the module mqtt:
const mqttNow = require('mqtt-now');
const options = {
host: 'localhost',
interval: 1000,
actions: [
{
topic: 'public',
message: 'my message'
},
{
topic: 'random',
message: () => ( 'random ' + Math.random() )
}
]
}
mqttNow.publish(options);

window.WebSocket - window is not defined

I am a bit out of my comfort zone here, so looking for a bit of guidance. I am trying to access an api to display live metrics, using phonic-elixir (https://www.npmjs.com/package/phoenix-elixir) - am just sort of trying to get it running first, so have loaded up their example code and connecting to an api (forgive me if the terminology is all wrong, I am new at this!)
This is my code:
import {Socket} from 'phoenix-elixir';
let socket = new Socket('ws://API_URL_HERE', {params: {'auth-token': 'AUTH_TOKEN'}})
socket.connect()
let channel = socket.channel('updates:new', {})
channel.join()
.receive('ok', resp => { console.log('Joined successfully', resp) })
.receive('error', resp => { console.log('Unable to join', resp) })
channel.on('update', payload => {
console.log('Received: ' + payload);
console.log(payload);
})
export default socket
When I run babel index.js | node I am getting the error: this.transport = opts.transport || window.WebSocket || LongPoll; and ReferenceError: window is not defined
Just some advice to point me in the right direction would be fantastic. Is window not defined because it needs a dom? Do I need a server to run this in?
Thank you :)
I just ported the client to be compatible with node.JS.
Here is the link https://github.com/mcampa/phoenix-channels
The difference with the original client is that this does not use long-polling and you need to pass the absolute url instead of the relative url.
To install it run:
npm install --save phoenix-channels
Same API as the original:
const { Socket } = require('phoenix-channels')
let socket = new Socket("ws://example.com/socket")
socket.connect()
// Now that you are connected, you can join channels with a topic:
let channel = socket.channel("room:lobby", {})
channel.join()
.receive("ok", resp => { console.log("Joined successfully", resp) })
.receive("error", resp => { console.log("Unable to join", resp) })
phoenix-elixir is client-side library that is supposed to be used in browsers not in node environment. You should create html page with your code and open it in browser to test it out.

Categories

Resources