I'm building social media application using node js and react js, I have problem when it comes to video / audio calls;
case 1: i call from computer to mobile phone and both are in same network, it works--
case 2: i call from mobile phone browser to computer and both are in same network, remote stream does not work--
case 3: i call from different network, remote stream does not work;--
i tried to change turn and stun servers but it did not work either;
The code;
function createPeer(userID: string, type: 'audio' | 'video') {
const peer = new RTCPeerConnection(configuration);
peer.ontrack = onTrackEvent;
peer.onicecandidate = onIceCandidateEvent(userID);
return peer;
}
function onTrackEvent(e: RTCTrackEvent) {
if (remoteStream.current) {
e.streams[0].getTracks().forEach((track) => {
remoteStream.current!.addTrack(track)
});
}
}
function onIceCandidateEvent (userID: string) {
return (e: RTCPeerConnectionIceEvent) => {
if (e.candidate) {
socket.emit('ice-candidate', {
userID,
candidate: e.candidate.candidate,
sdpMLineIndex: e.candidate.sdpMLineIndex,
sdpMid: e.candidate.sdpMid
})
}
}
}
function handlingAnswer({ sdp, myData, type }: { sdp: RTCSessionDescriptionInit, myData: any, type: 'audio' | 'video' } ) {
if (peerConnection.current) {
const desciption = new RTCSessionDescription(sdp);
peerConnection.current.setRemoteDescription(desciption)
.then(() => {
if (type === 'video') {
dispatch(callActions.gettingAnswerVideoCall(myData));
}
if (type === 'audio') {
dispatch(callActions.gettingAnswerVoiceCall(myData));
}
})
}
}
const makeCall = async (userID: string, type: 'audio' | 'video') => {
let constraints: MediaStreamConstraints = {};
if (type === 'video') {
constraints = {
video: true, audio: true
}
}
if (type === 'audio') {
constraints = {
audio: true
}
}
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
localStream.current = stream;
remoteStream.current = new MediaStream();
peerConnection.current = createPeer(userID, type);
localStream.current.getTracks().forEach((track) => {
peerConnection.current!.addTrack(track, localStream.current!)
});
const sdp = await peerConnection.current!.createOffer();
await peerConnection.current!.setLocalDescription(sdp);
const payload = {
to: userID,
caller: {
_id: userData!._id,
name: userData!.name,
username: userData!.username,
picture: userData!.picture
},
sdp,
type
}
dispatch(callActions.callUser({
callType: type,
userID
}))
socket.emit('offer', payload)
} catch (error) {
console.log(error);
}
}
async function acceptCall(userID: string, sdp: RTCSessionDescriptionInit, type: 'video' | 'audio') {
let constraints: MediaStreamConstraints = {};
if (type === 'video') {
constraints = { video: true, audio: true }
}
if (type === 'audio') {
constraints = { audio: true }
}
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
localStream.current = stream;
remoteStream.current = new MediaStream();
peerConnection.current = createPeer(userID, type);
localStream.current.getTracks().forEach((track) => {
peerConnection.current!.addTrack(track, localStream.current!)
})
const sessionDescription = new RTCSessionDescription(sdp);
await peerConnection.current.setRemoteDescription(sessionDescription);
const answer = await peerConnection.current.createAnswer();
await peerConnection.current.setLocalDescription(answer)
if (type === 'audio') {
dispatch(callActions.acceptVoiceCall())
}
if (type === 'video') {
dispatch(callActions.acceptVideoCall())
}
const payload = {
caller: userID,
sdp: answer,
myData: {
_id: userData!._id,
name: userData!.name,
username: userData!.username,
picture: userData!.picture
},
type
}
socket.emit('answer', payload)
} catch (error) {
alert(JSON.stringify(error))
}
}
socket.on('offer', handlingOffer);
socket.on('answer', handlingAnswer);
socket.on('ice-candidate', async ({ candidate, sdpMLineIndex, sdpMid }) => {
if (peerConnection.current) {
const rtcIceCandidate = new RTCIceCandidate({ candidate, sdpMLineIndex, sdpMid });
await peerConnection.current.addIceCandidate(rtcIceCandidate)
}
})
// In the Call Component
function CallComponent() {
useEffect(() => {
remoteVideoRef.current.srcObject = remoteStream.current
myVideoRef.current.srcObject = localStream.current
}, [])
return JSX .............................
}
Related
I'm using #aws-sdk/client-pinpoint to send an email to a verified user.
async sendEmail(body: any): Promise<void> {
const fromAddress = 'test#domain.com';
const toAddress = 'test#domain.com';
const projectId = 'XXX-XXXX-XXXX';
const subject = 'Amazon Pinpoint Test (AWS SDK for JavaScript in Node.js)';
const body_text = `Amazon Pinpoint Test (SDK for JavaScript in Node.js)`;
const charset = 'UTF-8';
const params = {
ApplicationId: projectId,
MessageRequest: {
Addresses: {
[toAddress]: {
ChannelType: 'EMAIL',
},
},
MessageConfiguration: {
EmailMessage: {
FromAddress: fromAddress,
SimpleEmail: {
Subject: {
Charset: charset,
Data: subject,
},
HtmlPart: {
Charset: charset,
Data: 'body_html',
},
TextPart: {
Charset: charset,
Data: body_text,
},
},
},
},
},
};
try {
const data = await this.pinpointClient.send(new SendMessagesCommand(params));
const { MessageResponse } = data;
if (!MessageResponse || !MessageResponse.Result) throw Error('Failed!');
const recipientResult = MessageResponse?.Result[toAddress];
if (recipientResult.StatusCode !== 200) {
throw new Error(recipientResult.StatusMessage);
} else {
console.log(recipientResult.MessageId);
}
} catch (err) {
console.log(err.message);
}
}
And everything is working fine. But when I try to use a pre-defined template, it is not being send for some reason and no errors were shown as well! I'm lost on how to pass template Name/ARN with substitution. Any idea on how to achieve that?
Cheers!
use Template Configuration in message configuration
TemplateConfiguration: {
EmailTemplate: {
'Name': 'template name',
'Version': 'latest'
}
}
async sendEmail(body: any): Promise<void> {
const fromAddress = 'test#domain.com';
const toAddress = 'test#domain.com';
const projectId = 'XXX-XXXX-XXXX';
const subject = 'Amazon Pinpoint Test (AWS SDK for JavaScript in Node.js)';
const body_text = `Amazon Pinpoint Test (SDK for JavaScript in Node.js)`;
const charset = 'UTF-8';
const params = {
ApplicationId: projectId,
MessageRequest: {
Addresses: {
[toAddress]: {
ChannelType: 'EMAIL',
},
},
MessageConfiguration: {
EmailMessage: {
FromAddress: fromAddress,
SimpleEmail: {
Subject: {
Charset: charset,
Data: subject,
},
HtmlPart: {
Charset: charset,
Data: 'body_html',
},
TextPart: {
Charset: charset,
Data: body_text,
},
},
},
},
TemplateConfiguration: {
EmailTemplate: {
'Name': 'template name',
'Version': 'latest'
}
}
},
};
try {
const data = await this.pinpointClient.send(new SendMessagesCommand(params));
const { MessageResponse } = data;
if (!MessageResponse || !MessageResponse.Result) throw Error('Failed!');
const recipientResult = MessageResponse?.Result[toAddress];
if (recipientResult.StatusCode !== 200) {
throw new Error(recipientResult.StatusMessage);
} else {
console.log(recipientResult.MessageId);
}
} catch (err) {
console.log(err.message);
}
}
Use this function to flatten the response returned from strapi on version 4. Helps you get rid of data and attributes properties
This will give you the same response structure as version 3 of strapi. This would help you migrate to version 4 from version 3 easily.
How to use it?
import the file.
const flattnedData = flattenObj({...data})
NOTE: The data here is the response returned from strapi version 4.
export const flattenObj = (data) => {
const isObject = (data) =>
Object.prototype.toString.call(data) === "[object Object]";
const isArray = (data) =>
Object.prototype.toString.call(data) === "[object Array]";
const flatten = (data) => {
if (!data.attributes) return data;
return {
id: data.id,
...data.attributes,
};
};
if (isArray(data)) {
return data.map((item) => flattenObj(item));
}
if (isObject(data)) {
if (isArray(data.data)) {
data = [...data.data];
} else if (isObject(data.data)) {
data = flatten({ ...data.data });
} else if (data.data === null) {
data = null;
} else {
data = flatten(data);
}
for (const key in data) {
data[key] = flattenObj(data[key]);
}
return data;
}
return data;
};
In my case I created a new middleware "flatten-response.js" in "middlewares" folder.
function flattenArray(obj) {
return obj.map(e => flatten(e));
}
function flattenData(obj) {
return flatten(obj.data);
}
function flattenAttrs(obj) {
let attrs = {};
for (var key in obj.attributes) {
attrs[key] = flatten(obj.attributes[key]);
}
return {
id: obj.id,
...attrs
};
}
function flatten(obj) {
if(Array.isArray(obj)) {
return flattenArray(obj);
}
if(obj && obj.data) {
return flattenData(obj);
}
if(obj && obj.attributes) {
return flattenAttrs(obj);
}
for (var k in obj) {
if(typeof obj[k] == "object") {
obj[k] = flatten(obj[k]);
}
}
return obj;
}
async function respond(ctx, next) {
await next();
if (!ctx.url.startsWith('/api')) {
return;
}
ctx.response.body = flatten(ctx.response.body.data)
}
module.exports = () => respond;
And I called it in "config/middlewares.js"
module.exports = [
/* ... Strapi middlewares */
'global::flatten-response' // <- your middleware,
'strapi::favicon',
'strapi::public',
];
I have to save the user permissions when the admin, in the user management page, choose what every user can (or can't) see.
After doing the cshtml page to show all the available pages, I have to save the changes through a typescript page:
Core.compatibility.ready(() => {
let editGestioneUtenti = document.getElementById("edit-gestioneRuoli");
if (editGestioneUtenti)
editGestioneUtenti.addEventListener("click", async ev => {
let id = Route.get("gestioneRuoli");
await edit(gestioneutenti, "/api/GestionePermessi/gestioneruoli/{Id}", id);
});
let salvaPermessi = document.getElementById("btn-save-permessi");
if (salvaPermessi)
salvaPermessi.addEventListener("click", async ev => {
ev.preventDefault();
let menu = [];
let tab = [];
let func = [];
const data = {
_id: val,
_menu: idmenu,
_tab: idtab,
_func: idfunc
};
var val = $("#Username").val();
$(".combomenu").each(function () {
menu.push($(this).val());
})
var idmenu = $("#menu").val();
$(".combomenu").each(function () {
menu.push($(this).val());
})
var idtab = $("#tab").val();
$(".combotab").each(function () {
tab.push($(this).val());
})
var idfunc = $("#func").val();
$(".combofunc").each(function () {
func.push($(this).val());
})
})
try {
await Core.compatibility.fetch("/api/gestionepermessi/gestioneruoli/", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
}).then(response => {
if (!response.ok) {
throw new Error(response.statusText)
} else {
$(".combomenu").each(function () {
jQuery.each(_menu, function (i, val) {
$("#" + val).remove();
})
})
}
}).then(response => {
$(".combotab").each(function () {
jQuery.each(_tab, function (i, val) {
$("#" + val).remove();
})
})
}).then(resp => {
$(".combofunc").each(function () {
jQuery.each(_func, function (i, val) {
$("#" + val).remove();
})
});
})
} catch (e) {
SwalWrapper.fire({
type: "error",
title: "Errore",
text: e
});
};
});
This part of code contains some errors, indeed the compiler show me this messages:
cannot find name 'data'
cannot find name '_menu'
cannot find name '_tab'
cannot find name '_func'
but I've declared at line 18 of the code I've posted. How can I fix it?
I am new to the react-redux environment and have been working on a small project to get acquainted. At the moment, I am working on the login page and have successfully been able to retrieve the response whether successful or not. The problem I face is once I retrieve the response I dont know how to store and read what is in the response without a console.log.
import React from 'react';
import { connect } from 'react-redux';
import { Button, Input } from 'reactstrap';
import { IsEmpty } from '../../helpers/utils';
import { userActions } from '../../actions/user.actions';
import LoginLayoutComponent from '../layouts/loginLayout';
class LoginFormComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
Username: '',
Password: '',
submitted: false,
errors: {}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleValidation = this.handleValidation.bind(this);
}
handleChange(e) {
const { name, value } = e.target;
this.setState({ [name]: value });
}
handleSubmit(e) {
e.preventDefault();
let response = null;
let errors = {};
if (this.handleValidation()) {
this.setState({ submitted: true });
const { Username, Password } = this.state;
if (Username && Password) {
response = JSON.stringify(userActions.login(Username, Password));
console.log(response);
if (response != null) {
errors["Error"] = "Invalid Username or Password";
this.setState({
errors: errors
});
}
}
}
}
handleValidation() {
let isValid = true;
let errors = {};
if (this.state.submitted === true && IsEmpty(this.state.Username)) {
errors["Username"] = "Username is required";
isValid = false;
}
if (this.state.submitted === true && IsEmpty(this.state.Password)) {
errors["Password"] = "Password is required";
isValid = false;
}
this.setState({
errors: errors
});
return isValid;
}
render() {
const { Username, Password, submitted, errors } = this.state;
//var errorMessage = loginErrorMessage;
return (
<LoginLayoutComponent>
<div className="panel panel-default">
<div className="panel-heading"></div>
<div className="panel-body" autoFocus={false}>
<form method="post" name="LoginForm" onSubmit={this.handleSubmit}>
<div className='form-group row'>
<input className='form-control' type="text" placeholder="Username" name="Username" value={Username} onChange={this.handleChange} autoFocus />
{!IsEmpty(errors.Username) && <p>{errors.Username}</p>}
</div>
<div className='form-group row' >
<Input className="form-control" type="Password" placeholder="Password" name="Password" value={Password} onChange={this.handleChange} />
{!IsEmpty(errors.Password) && <p>{errors.Password}</p>}
</div>
<Button className="btn btn-warning btn-block" onClick={this.handleSubmit}>Login</Button>
</form>
{!IsEmpty(errors.Response) && <p><b>Login Failed</b>.{errors.Response}</p>}
</div>
</div>
</LoginLayoutComponent>
);
}
}
function mapStateToProps(state) {
//const { loading } = state.authentication;
return {
// loginErrorMessage: state.authentication.error && state.authentication.error.message
};
}
const LoginForm = connect(mapStateToProps)(LoginFormComponent);
export { LoginForm };
=======================================================================
Action
import { history } from '../helpers/history';
import { userService } from '../services/user.service';
import { userConstants } from '../constants/user.constants';
export const userActions = {
login,
logout
};
function login(Username, Password) {
//return dispatch => {
console.log('Action begin');
userService.login(Username, Password)
.then(
results => {
if (results.username) {
console.log('success');
history.push('/home');
return { type: userConstants.LOGIN_SUCCESS, Username };
}
}, error => {
return { error };
}
);
//};
}
====================================================================
Service
import { HandleResponse, Logout } from '../helpers/utils';
export const userService = {
login,
logout,
_setUserSession
};
function login(Username, Password) {
const requestOptions = {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json; charset=utf-8'
}),
body: JSON.stringify({
Username,
Password
})
};
const requestPath = "http://localhost:53986/api/login/postlogin";
console.log('Start Fetching');
return fetch(requestPath,requestOptions)
.then(HandleResponse)
.then(response => {
var result = response && response.results && response.results.length > 0 ? response.results[0] : null;
if (result) {
console.log('Setting session');
_setUserSession(result);
}
return {result};
}).catch(function (error) {
return Promise.reject(error);
});
}
// Login successful :: store user details
function _setUserSession(user) {
if (user.id) {
localStorage.setItem('user', JSON.stringify(user));
}
}
===========================================
IsEmpty (As requested)
export function IsEmpty(param) {
return param === null || param === undefined || param === "" || (typeof param === "object" && param.length === 0) || param === false || param === 0;
}
The expected result is to have the error displayed in the response and display it on the login form to the user.
The problem is the way you use promises in both login functions.
function login(Username, Password) {
//return dispatch => {
console.log('Action begin');
userService.login(Username, Password)
.then(
results => {
if (results.username) {
console.log('success');
history.push('/home');
return { type: userConstants.LOGIN_SUCCESS, Username };
}
}, error => {
return { error };
}
);
//};
}
When you return in this function, it returns for the then callback but not for the login function.
You could fix your functions with es6 async/await syntax (code could be wrong but the idea is here):
async function login(Username, Password) {
try {
const res = await userService.login(Username, Password);
if (results.username) {
console.log('success');
history.push('/home');
return { type: userConstants.LOGIN_SUCCESS, Username };
}
} catch (e) {
return error;
}
}
async function login(Username, Password) {
const requestOptions = {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json; charset=utf-8'
}),
body: JSON.stringify({
Username,
Password
})
};
const requestPath = "http://localhost:53986/api/login/postlogin";
console.log('Start Fetching');
const response = HandleResponse(await fetch(requestPath,requestOptions));
const result = response && response.results && response.results.length > 0 ? response.results[0] : null;
if (result) {
console.log('Setting session');
_setUserSession(result);
}
return result;
}
Hello i am new to node and i am trying to save data in mongoose. The problem is that there are 3 collections Units, Building and Section. The Schema of Building is :
var buildingsSchema=new Schema({
buildingname:String,
status:String
});
Schema of Section is :
var sectionsSchema=new Schema({
section_type:String,
buildings:{ type: Schema.Types.ObjectId, ref: 'buildings' },
status:String
});
Schema of Units is :
var unitsSchema=new Schema({
unit_type:String,
unit_num:String,
unit_ac_num:Number,
buildings:{ type: Schema.Types.ObjectId, ref: 'buildings' },
sections:{ type: Schema.Types.ObjectId, ref: 'sections' },
shares:Number
});
in Section there is an Id of Building and in Units there is Id's of both Building & Section
now i have used xlsx plugin to convert uploaded excel file to json by :-
var wb = XLSX.readFile("uploads/xls/" + req.file.filename);
data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1});
and to map it into json object and saving i am using Async Waterfall Model
for (var index = 1; index < data.length - 1 ; index++) {
var ele= data[index];
// console.log(ele);
var d = { // this is an object which will hold data
record_id: ele[0],
residenceone_unit_id : ele[1],
official_unit_id: ele[2],
building: ele[3],
unit_type : ele[4],
section: ele[5],
shares: ele[6],
unit_style : ele[7]
}
// console.log(d);
var unt = new Units(); // to save units
unt = {
unit_type: d.unit_type,
unit_num: d.residenceone_unit_id,
unit_ac_num: d.official_unit_id,
buildings: '', // empty because need to put id of that particular building
sections: '', // empty because need to put id of that particular sections
shares:d.shares
}
async.waterfall([
function (callback) {
// find building first
Buildings.findOne({buildingname : ele.building})
.exec(function (err,doc) {
if (err) {
return callback(err);
}
// if no building then save one
else if (!doc) {
// console.log("Building is going to save")
var build = new Buildings();
build.buildingname = d.building;
build.status = "active";
build.save(function (err,dc) {
if (err) {
return callback(err);
}
else {
// assign id of building to unit
unt.buildings = dc._id ;
callback(null);
}
})
}
else {
// if building is there then no need to save assign id of it to units
// console.log("Building already exists;")
unt.buildings = doc._id ;
// execute second function
callback(null);
}
// callback(null);
})
},
function (callback) {
// same as building find section of that building first with building Id and section type
Sections.findOne({buildings : unt.buildings,section_type: d.section})
.exec(function (err,doc) {
if (err) {
return callback(err);
}
if (!doc) {
// if no section of that building is there then save one
// console.log("Section needs to be save")
var sect = new Sections();
sect.section_type = d.section;
sect.buildings = unt.buildings;
sect.status = "active";
sect.save(function (err,dc) {
if (err) {
return callback(err);
}
else {
// assign its id to unit
// console.log("Section is saved")
unt.sections = dc._id;
// execute third function
callback(null);
}
})
}
else {
// if there is section of that building id is available than assign id to units
// console.log("Section already exists");
unt.sections = doc._id;
// execute third function
callback(null);
}
})
},
function (callback) {
// there is no need to seaarch just need to save unit
// console.log("Units is going to save")
// console.log(unt);
unt.save(function (err, doc) {
if (err) {
} else if (doc){
// console.log("Unit Saved");
// console.log(doc);
}
})
}
])
}
}
its working but every time instead of searching of data in mongodb it save everytime. Duplication is the main problem if any other way to save units in mongodb will help me a lot.
first i have save Buildings and section :
async.every(uniqueSection,function (uS,callback) {
if (uS != undefined) {
console.log(uS);
Buildings.findOne({buildingname:uS.building}, function (err,doc) {
if (doc) {
// console.log(doc);
Sections.findOne({buildings:doc._id,section_type:uS.section},function (er,sd) {
if (sd) {
// then dont save
console.log(sd);
}
if (er) {
console.log(er);
}
if (!sd) {
// then save
var sect = new Sections();
sect.buildings = doc._id;
sect.section_type = uS.section;
sect.status = 'active';
sect.save(function (err,st) {
if(err) console.log(err);
console.log(st);
})
}
})
}
if (!doc) {
if (uS.building != undefined) {
var building = new Buildings();
building.buildingname = uS.building;
building.status = "active";
building.save(function (er,dc) {
if (dc) {
// console.log(dc);
Sections.findOne({buildings:dc._id,section_type:uS.section},function (er,sd) {
if (sd) {
// then dont save
console.log(sd);
}
if (er) {
console.log(er);
}
if (!sd) {
// then save
var sect = new Sections();
sect.buildings = dc._id;
sect.section_type = uS.section;
sect.status = 'active';
sect.save(function (err,st) {
if(err) console.log(err);
console.log(st);
})
}
})
}
if (er) {
console.log(er);
}
})
}
}
if (err) {
console.log(err);
}
})
}
})
then i have saved Units by :
async.waterfall([
function(callback) {
Buildings.findOne({buildingname:d.building}, function (err,doc) {
if (doc) {
buildingId = doc._id;
callback(null, doc);
}
if (err) {
console.log(err);
}
})
},
function(doc,callback) {
Sections.findOne({buildings: buildingId,section_type:d.section},function (er,sd) {
if (sd) {
sectionId = sd._id;
callback(null,doc,sd);
}
if (er) {
console.log(er);
}
})
},
function (bld,st,callback) {
var s = d.shares.replace(",","");
var unit = {
unit_type: d.unit_type,
unit_num: d.residenceone_unit_id,
unit_ac_num: d.official_unit_id,
buildings: bld._id,
sections: st._id,
shares: s
}
Units.findOne(unit,function (err,unt) {
if (err) {
console.log(err);
}
if(unt) {
console.log(unt)
}
if (!unt) {
var units = new Units();
units.unit_type = d.unit_type;
units.unit_num = d.residenceone_unit_id;
units.unit_ac_num = d.official_unit_id;
units.buildings = bld._id;
units.sections = st._id;
units.shares = s;
units.save(function (er,doc) {
if (er) console.log(er);
console.log(doc);
})
}
})
}
], function(err) {
console.log(err)
});