Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local offer sdp: Called in wrong state: have-remote-offer - socket.io

While calling to another user getting this error
"Uncaught (in promise) DOMException: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local offer sdp: Called in wrong state: have-remote-offer".
Receiver is able to see both local and remote stream but caller not able to see remote stream.
switch(type){
case 'client-candidate':
if(pc.localDescription){
await pc.addIceCandidate(new RTCIceCandidate(data));
}
break;
case 'is-client-ready':
if(!pc){
await getConn();
}
if(!localStream){
await getCam();
}
if(pc.iceConnectionState === 'connected'){
send('clent-already-oncall', null, presentUserId, null);
}else{
displayCall(incomingData);
$(document).on('click', '#declineBtn', function(){
send('client-rejected', sendTo, currentUserName, presentUserId, null);
$('#incomingCallModel').modal('toggle');
});
$(document).on('click', '#answerBtn', function(){
send('client-is-ready', sendTo, currentUserName, presentUserId, null);
$('#incomingCallModel').modal('toggle');
createOffer(sendTo, presentUserId);
});
}
break;
case 'client-answer':
if(pc.localDescription){
await pc.setRemoteDescription(data);
}
break;
case 'client-offer':
createAnswer(sendTo, presentUserId, data);
break;
case 'client-is-ready':
createOffer(sendTo, presentUserId);
break;
case 'client-rejected':
alert('Client has rejected your call');
break;
case 'clent-already-oncall':
setTimeout(() => {
alert('client is on other call');
window.location.reload(true);
}, 2000);
break;
}
let pc;
function getConn(){
if(!pc){
pc = new RTCPeerConnection();
}
}
async function getCam(){
try{
if(!pc){
await getConn();
}
mediaStream = await window.navigator.mediaDevices.getUserMedia(mediaConst);
localVideo.srcObject = mediaStream;
localStream = mediaStream;
localStream.getTracks().forEach(track => pc.addTrack(track, localStream));
}catch(error){
// alert('Camera not found')
console.log(error);
}
}
function displayCall(incomingData){
$('.incoming-call-user-name').text(incomingData.callingUserName);
let calligUserProfile = $("#allUserList").find("[data-id='" + incomingData.callingUserId + "']").data("profile");
$('.calling-user-pic').attr('src', calligUserProfile);
$('#incomingCallModel').modal('show');
}
function send(type, sendTo, callingUserName, callingUserId, data){
socket.emit('sendChatRequest', JSON.stringify({
type: type,
receiverId: sendTo,
callingUserName: callingUserName,
callingUserId: callingUserId,
data: data,
}));
}
async function createOffer(sendTo, calledById){
if(!pc){
await getConn();
}
if(!localStream){
await getCam();
}
await pc.createOffer(options);
await sendIceCandidate(sendTo,calledById);
await pc.setLocalDescription(pc.localDescription);
send('client-offer', sendTo, currentUserName, calledById, pc.localDescription);
}
async function sendIceCandidate(sendTo, calledById){
pc.onicecandidate = event => {
if(event.candidate !== null){
send('client-candidate', sendTo, currentUserName, calledById, event.candidate);
}
}
pc.ontrack = event => {
console.log(event)
$('#video').removeClass('hide');
$('#video').addClass('show');
$('#videoCall').addClass('hide');
if (remoteVideo.srcObject) return;
remoteVideo.srcObject = event.streams[0];
}
}
async function createAnswer(sendTo, presentUserId, data){
if(!pc){
await getConn();
}
if(!localStream){
await getCam();
}
await sendIceCandidate(sendTo, presentUserId);
await pc.setRemoteDescription(data);
await pc.createAnswer();
await pc.setLocalDescription(pc.localDescription);
send('client-answer', sendTo, currentUserName, presentUserId, pc.localDescription);
}

Possible reasons.
check weather you are trying to set the remote answer again after setting it for first time.
check weather your onTrack event is firing in the caller side.
Possible reasons of onTrack not firing
check whether you are adding local tracks to your peer before creating offer or answer.
Make sure your addTrack is in the memory before the exchange of offer , answer , candidate happens.

Related

`next.js` api is resolved before promise fullfill?

I want to achieve something like this:
call my website url https://mywebsite/api/something
then my next.js website api will call external api
get external api data
update external api data to mongodb database one by one
then return respose it's status.
Below code is working correctly correctly. data is updating on mongodb but when I request to my api url it respond me very quickly then it updates data in database.
But I want to first update data in database and then respond me
No matter how much time its take.
Below is my code
export default async function handler(req, res) {
async function updateServer(){
return new Promise(async function(resolve, reject){
const statusArray = [];
const apiUrl = `https://example.com/api`;
const response = await fetch(apiUrl, {headers: { "Content-Type": "application/json" }});
const newsResults = await response.json();
const articles = await newsResults["articles"];
for (let i = 0; i < articles.length; i++) {
const article = articles[i];
try {
insertionData["title"] = article["title"];
insertionData["description"] = article["description"];
MongoClient.connect(mongoUri, async function (error, db) {
if (error) throw error;
const articlesCollection = db.db("database").collection("collectionname");
const customQuery = { url: article["url"] };
const customUpdate = { $set: insertionData };
const customOptions = { upsert: true };
const status = await articlesCollection.updateOne(customQuery,customUpdate,customOptions);
statusArray.push(status);
db.close();
});
} catch (error) {console.log(error);}
}
if(statusArray){
console.log("success", statusArray.length);
resolve(statusArray);
} else {
console.log("error");
reject("reject because no statusArray");
}
});
}
updateServer().then(
function(statusArray){
return res.status(200).json({ "response": "success","statusArray":statusArray }).end();
}
).catch(
function(error){
return res.status(500).json({ "response": "error", }).end();
}
);
}
How to achieve that?
Any suggestions are always welcome!

Why is my lambda taking exactly 6 seconds every time to respond?

I am using NodeJS env with serverless framework.
The service is an endpoint for a contact form submission. Code looks something like this.
I have two async calls, one is writing to dynamoDB and another is sending an Email via SES.
module.exports.blog = async (event, context, callback) => {
const data = JSON.parse(event.body);
const handler = 'AB';
const sesParams = getSesParams(handler, data);
if (typeof data.text !== 'string') {
callback(null, validationErrRes);
return;
}
try {
await logToDB(handler, data);
} catch (dbErr) {
console.error(dbErr);
callback(null, errRes(dbErr, 'Failed to log to DB'));
return;
}
try {
await SES.sendEmail(sesParams).promise();
} catch (emailErr) {
console.error(emailErr);
callback(null, errRes(emailErr, 'Failed to send mail'));
return;
}
callback(null, succsessResponse);
return;
};
The response takes exactly 6sec when the dbput and sendMail takes total of < 300ms.
PS: Running both async calls parallelly does not help much.
Try removing the callback in your function definition and the call to your callback function. Just return the successResponse. You are already an async function so do not need to use a callback. You can also just return error.
module.exports.blog = async (event, context) => {
and
return {
statusCode: 200
}
and
return validationErrRes

Error converting assert.fail to async-await from functions not working

I am trying to convert some test codes to work using the async await syntax. The above portion code using async-await is not working while the lower portion code using then is working fine.
Can anyone advise me how I should correct the code to make it work? Thanks
NOT WORKING
it("transfers token ownership", async () => {
tokenInstance = await DappToken.deployed();
try {
return tokenInstance.transfer.call(accounts[1], "9999999999999999");
} catch (error) {
console.log("error ", error);
assert(
error.message.indexOf("revert") >= 0,
"Error message must contain revert"
);
}
});
WORKING
it("transfers token ownership", function() {
return DappToken.deployed()
.then(function(instance) {
tokenInstance = instance;
return tokenInstance.transfer.call(accounts[1], 9999999999999999999);
})
.then(assert.fail)
.catch(function(error) {
// console.log("error", error);
assert(
error.message.toString().indexOf("invalid") >= 0,
"error message must contain revert"
);
return tokenInstance.transfer.call(accounts[1], 250000, {
from: accounts[0]
});
})
Following code works!
hope this will help someone else :)
it("transfers token ownership", async () => {
tokenInstance = await DappToken.deployed();
try {
await tokenInstance.transfer.call(accounts[1], "9999999999999999");
assert(false);
} catch (error) {
assert(
error.message.indexOf("revert") >= 0,
"Error message must contain revert"
);
}
});

How to use async and await in gmail read message API

I tried using async/await instead of the callback for reading the Gmail
Here is the code snippet
const {google} = require('googleapis');
async function getRecentMessageBody(auth) {
const gmail = google.gmail({version: 'v1', auth});
try{
const messageId = await gmail.users.messages.list({
userId: 'me',
labelIds: 'INBOX',
maxResults: 1
});
const message = await gmail.users.messages.get({
userId: 'me',
id: messageId.data.messages[0].id,
format : 'full'
});
const value = base64url.decode(message.data.payload.body.data);
console.log(messageId);
//return value ;
}
catch(error) {
console.log('Error occurs while reading mail :'+ error);
throw error;
}
}
But the messageId is undefined
whereas if i use
gmail.users.labels.list({
userId: 'me',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const labels = res.data.labels;
if (labels.length) {
console.log('Labels:');
labels.forEach((label) => {
console.log(`- ${label.name}`);
});
} else {
console.log('No labels found.');
}
});
how to fix the issue??
use promisfy to convert callback to promises

Issue with Promise

I got a small problem with my function below. The Promise.map doesn't wait for Folder.create to be finished and iterate through the next value.
Promise.map(name, function(na){
return fs.stat(na.url, function(err, stats){
if (typeof stats === 'undefined'){
console.log("file doesn't exist");
return Folder.create(na).then(function(fd){
return mkdirp(root + product.url).then(function(){
console.log("Folder Created");
return null;
});
}, function(err){
console.log(err);
return reject({message: "Error when creating the folder"});
});
}
});
}).then(function(){
console.log('Iteration Done');
return resolve({message: "Folder Created!"});
});
// I GOT :
//file doesn't exist
//file doesn't exist
//file doesn't exist
//Iteration Done
//file doesn't exist
//file doesn't exist
//file doesn't exist
//Iteration Done
//Folder Created
//Folder Created
//Folder Created
//Folder Created
//Folder Created
//Folder Created
There are a couple issues here:
Promise.map() runs the operations for each array element in parallel, not serially. If you want them run serially, you can pass {concurrency: 1} as an option to Promise.map() or use Promise.mapSeries().
fs.stat() does not return a promise so your main callback to Promise.map() isn't returning a promise so the whole Promise.map() infrastructure does not know how to wait for any of your results. You can promisify fs.stat() to solve that issue.
You appear to be using an anti-pattern with your resolve() and reject() calls in here. You don't show the outer definition where those come from, but you should be just using the promise returned from Promise.map() rather than doing that.
Here's how they can successfully be run in parallel:
var fs = Promise.promisifyAll(require('fs'));
Promise.map(name, function(na){
return fs.statAsync(na.url).then(function(err, stats){
if (typeof stats === 'undefined'){
console.log("file doesn't exist");
return Folder.create(na).then(function(fd){
return mkdirp(root + product.url).then(function(){
console.log("Folder Created");
return null;
});
}, function(err){
console.log(err);
return Promise.reject({message: "Error when creating the folder"});
});
}
});
}).then(function(){
console.log('Iteration Done');
return ({message: "Folder Created!"});
});
If you wanted to run your operations serially with Bluebird, you could pass {concurrency: 1} to Promise.map():
Promise.map(name, fn, {concurrency: 1}).then(...);
Or use:
Promise.mapSeries(name, fn).then(...)
fs.stat is a callback type function and thus, does not return a Promise. You should modify your code to be something like this
// This might not work directly. I haven't tried to run it
Promise.map(name, function(na) {
return new Promise(function(resolve, reject) {
fs.stat(na.url, function(err, stats) {
if (typeof stats === 'undefined') {
console.log("file doesn't exist");
Folder.create(na).then(function(fd) {
return mkdirp(root + product.url);
}).then(function() {
console.log("Folder Created");
resolve();
}).catch(function(err) {
console.log(err);
reject({
message: "Error when creating the folder"
});
});
} else {
resolve();
}
});
});
}).then(function() {
console.log('Iteration Done');
return {
message: "Folder Created!"
};
});

Resources