I'm new to expo and I trying expo-auth-session for discord but return "validation error auth url must be a valid uri"
This is my code
const { authorize, clientId, scopes } = discord;
const useProxy = true;
const redirectUri = makeRedirectUri({ useProxy });
export default function Login() {
const discovery = useAutoDiscovery(authorize);
const [request, response, promptAsync] = useAuthRequest(
{
clientId,
redirectUri,
scopes,
},
discovery
);
useEffect(() => {
console.log(response)
}, [response]);
const onLogin = async () => {
promptAsync({useProxy}).catch(e =>{
console.log(e);
})
};
return (
<View>
<Button title="Login" disabled={!request} onPress={onLogin} />
</View>
);
}
Related
I'm having an issue implementing SSO with AWS Amplify into my React Native app. I have SSO working fine, however, when trying to put the cognito user object in my authentication context, Hub.listen calls a signout and the user is immediately signed out.
Here is my code where user is signed up:
SignUp.js
...
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data } }) => {
console.log("event", event);
console.log("data", data);
switch (event) {
case "signIn":
console.log("data from signup: ",data)
setUserInContext(data);
break;
case "signOut":
setUserInContext(null);
break;
case "customOAuthState":
setCustomState(data);
}
})
return unsubscribe;
}, []);
...
return (
...
<Button
onPress={() => Auth.federatedSignIn({provider: "Google"})}
>
Google
</Button>
...
)
This code properly opens the google consent screen and allows me to select a user to login with. In fact, if I don't send the returned user object from the to the context like setUserInContext(data) in the above code, I get the user and everything works. However, sending this data to my context seems to cause Hub.listen to detect or invoke the oauth signout, even if I add something like this:
...
const [authUser,setAuthUser] = useState(null)
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data } }) => {
console.log("event", event);
console.log("data", data);
switch (event) {
case "signIn":
console.log("data from signup: ",data)
setAuthUser(data);
break;
case "signOut":
setAuthUser(null);
break;
case "customOAuthState":
setCustomState(data);
}
})
return unsubscribe;
}, []);
useEffect(() => {
if (authUser) {
console.log("authuser activated")
loginWithGoogle(authUser)
}
},[authUser])
...
return (
...
<Button
onPress={() => Auth.federatedSignIn({provider: "Google"})}
>
Google
</Button>
...
)
Below is my code for my authentication context:
export const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
useEffect(() => {
Auth.currentAuthenticatedUser()
.then(user => {
//fetchUserData(user).catch(err => console.error(err));
console.log("currentauthenticateduser: ",user)
setUser(user);
})
.catch((err) => {
console.log("no user found: ",user,"\nerr: ",err)
setUser(null)
});
},[]);
const login = (usernameOrEmail, password) =>
Auth.signIn(usernameOrEmail, password)
.then(cognitoUser => {
setUser(cognitoUser);
return cognitoUser;
})
.catch((err) => {
if (err.code === 'UserNotFoundException') {
err.message = 'Invalid username or password';
}
throw err;
}
);
const loginWithGoogle = (cognitoUser) => {
console.log("setting user: ",cognitoUser)
setUser(cognitoUser)
}
const logout = () =>
console.log("logout called")
Auth.signOut()
.then(data => {
setUser(null);
return data;
}
);
const deleteUser = async () => {
try {
const result = await Auth.deleteUser();
console.log(result);
} catch (err) {
console.log("Error deleting user", err);
} finally {
setUser(null);
}
}
const values = useMemo(() => ({
user,
loginWithGoogle,
login,
logout,
deleteUser
}), [user]);
return (
<UserContext.Provider value={values}>{children}</UserContext.Provider>
)
}
export const useUser = () => {
const context = useContext(UserContext);
if (context === undefined) {
throw new Error('`useUser` must be within a `UserProvider` component');
}
return context;
};
Please send help
I'm having a hard time trying to fix my login page
I've provided a very short youtube video on what is the problem that I encountered.
Youtube Link: https://youtu.be/lpyJo6tmiRs
It works properly on localhost but breaks when I deploy to herkou & netlify.
Register function also works properly
I provided everything here and also hidden some important info like mongodb user and passwords.
Website Link
https://incomparable-speculoos-abdd5f.netlify.app/
Login Page
import React, { useState, useEffect } from 'react'
import { useNavigate } from "react-router-dom"
import Axios from 'axios'
import './login.css'
import Register from '../register/register'
const Login = () => {
const navigate = useNavigate();
const [style, setStyle] = useState('hidden')
const [border, setBorder] = useState(false)
const [email, setEmail] = useState('')
const [password, setPass] = useState('')
const [errMsg, setErr] = useState('')
Axios.defaults.withCredentials = true;
const handleEmail = (e) => {
setEmail(e.target.value)
}
const handlePassword = (e) => {
setPass(e.target.value)
}
const show = () => [
setStyle('registerParent')
]
const hide = () => {
setStyle('hidden')
}
const reloadA = () => {
window.location.reload(false);
}
// FUNCTION WHEN LOGIN IS CLICKED
const login = () => {
Axios.post('https://votereact-app.herokuapp.com/login',
{email: email,
password: password,
}).then((response) => {
// CHECKS IF THERE IS A MESSAGE FROM THE BACKEND (MEANS THERE IS A PROBLEM IN THE LOGIN)
if (response.data.message) {
setErr(response.data.message)
setBorder(true)
} else {
// NAVIGATES TO /home ROUTE OF THERE IS NO MESSAGE (/route redirects to privateRoute)
setErr("Logged in")
setBorder(false)
navigate('/home', {replace: true})
}
})
}
return (
<>
<div className="loginParent">
<div className="loginContainer">
<h1 className="vote-login">VoteReact</h1>
<div className="loginBox">
<div className="inputs-parent">
<input type="text" style={{border: border ? '1px solid #e2252b' : '1px solid #1B74E4'}} placeholder="Email" className="email-input" onChange={handleEmail}></input>
<input type="password" style={{border: border ? '1px solid #e2252b' : '1px solid #1B74E4'}}placeholder="Password" className="password-input" onChange={handlePassword}></input>
<p className="errMsg">{errMsg}</p>
</div>
<button className="loginButton" onClick={login}>Log in</button> {/* LOGIN BUTTON */}
<p className="forgot">Forgot Password?</p>
<button className="signup" onClick={show}>Sign up</button>
</div>
</div>
</div>
<Register styleName={style.toString()} close={() => hide()} load={() =>reloadA()}/>
</>
)
}
export default Login
BACK END CODE
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose")
const app = express();
const bcrypt = require("bcryptjs")
const saltRounds = 10;
const bodyParser = require("body-parser")
const cookieParser = require("cookie-parser")
const session = require("express-session")
const voterModel = require('./modules/voters.js')
const presidentModel = require('./modules/president.js')
const viceModel = require('./modules/vice.js')
const treasurerModel = require('./modules/treasurer.js')
app.use(express.json());
require('dotenv').config();
app.use(cors({credentials: true, origin: 'https://incomparable-speculoos-abdd5f.netlify.app'}));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }))
app.use(session({
key: "userId",
secret: "hidden",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 60000
}
}))
mongoose.connect("hidden",
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
// GET THE SESSION AND CHECK IF IT DOES EXIST OR NO
//IF YES THEN LOGGEDIN: TRUE ELSE, FALSE
// --- HERE IS WHERE I ENCOUNTER PROBLEM, IT SHOULD RETURN TRUE AFTER I LOG IN BUT STILL RETURNS FALSE ---
app.get('/login', async (req, res) => {
if (req.session.voter) {
res.send({loggedIn: true})
} else {
res.send({loggedIn: false})
}
})
app.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
// CHECKS IF USER EMAIL EXISTS
voterModel.find({email: email}, {"email":1}, async (err, result) => {
if (err) {
console.log(err)
} else {
if(result.length > 0) {
// COMPARES PASSWORD IF IT IS CORRECT
const user = await voterModel.findOne({email: email})
const pass = await user.comparePassword(password)
if (pass) {
// SAVE THE SESSION IF PASS IS CORRECT
req.session.voter = result
var oneWeek = 60 * 60 * 24; //1 week
req.session.voter.expires = new Date(Date.now() + oneWeek);
req.session.voter.maxAge = oneWeek;
console.log(req.session.voter)
res.send(result)
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
}
})
})
app.post('/register', async (req, res) => {
const username = req.body.username;
const email = req.body.email;
const password = req.body.password;
// HASING PASSWORD
bcrypt.hash(password, saltRounds, async (err, hash) => {
if (err) {
console.log(err)
}
// INSERTING VALUES
const voters = await voterModel({email: email, username: username, password: hash, status: false})
// CHECKS IF EMAIL IS IN USE
const isNewEmail = await voterModel.isThisEmailInUse(email)
if (!isNewEmail) return res.send({ message: 'This email is already taken!'})
// SAVES THE INSERT DATA FOR VOTERS
await voters.save()
res.send({success: true})
})
})
app.post('/logout', (req, res) => {
if(req.session.voter) {
req.session.voter = null;
req.session.destroy();
}
})
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log('Running on port successfuly')
})
Private Route to Home
import React, { useState, useEffect } from 'react'
import { useNavigate } from "react-router-dom"
import Axios from 'axios'
import Home from "./home/home.js"
const PrivateRoute = () => {
Axios.defaults.withCredentials = true;
const navigate = useNavigate();
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
// GET DATA FROM axios.get(/login) on backend
Axios.get("https://votereact-app.herokuapp.com/login").then((response) => {
if (response.data.loggedIn === true) {
setLoggedIn(true);
console.log(response)
} else {
navigate("/" , {replace: true})
console.log(response)
}
})
},[])
// WHILE CHECKING IF Logged in or not
if (!loggedIn) {
return (
<>
Loading...
</>
)
}
// Redirects to real home page if user is logged in
return (
<>
<Home/>
</>
)
}
export default PrivateRoute
Inside App.js I have auth validation (i am using useState, useMemo, useEffect) but when tried to impement splash screen and following Splas screen Dos I am getting Rendered more hooks than during the previous render. So following Rules of Hooks I put at top level useEffect and useState but now I am getting a new error Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function, in App I see I need to cancel async functions but I need them to request the server and validate users.
This is how my code was before implementing Splash screen:
export default function App() {
const [auth, setAuth] = useState(undefined);
useEffect(() => {
(async () => {
const token = await getTokenApi();
if (token) {
setAuth({
token,
idUser: jwtDecode(token).id,
});
} else {
setAuth(null);
}
})();
}, []);
const login = (user) => {
setTokenApi(user.jwt);
setAuth({
token: user.jwt,
idUser: user.user.id,
});
};
const logout = () => {
if (auth) {
removeTokenApi();
setAuth(null);
}
};
const authData = useMemo(
() => ({
auth,
login,
logout,
}),
[auth]
);
if (auth === undefined) return null;
return (
<AuthContext.Provider value={authData}>
<PaperProvider>{auth ? <AppNavigation /> : <Auth />}</PaperProvider>
</AuthContext.Provider>
);
This is how i got it now
export default function App() {
const [auth, setAuth] = useState(undefined);
useEffect(() => {
(async () => {
const token = await getTokenApi();
if (token) {
setAuth({
token,
idUser: jwtDecode(token).id,
});
} else {
setAuth(null);
}
})();
}, []);
const [appIsReady, setAppIsReady] = useState(false);
useEffect(() => {
async function prepare() {
try {
await SplashScreen.preventAutoHideAsync();
await Font.loadAsync(Entypo.font);
await new Promise((resolve) => setTimeout(resolve, 4000));
} catch (e) {
console.warn(e);
} finally {
setAppIsReady(true);
}
}
prepare();
}, []);
const login = (user) => {
setTokenApi(user.jwt);
setAuth({
token: user.jwt,
idUser: user.user.id,
});
};
const logout = () => {
if (auth) {
removeTokenApi();
setAuth(null);
}
};
const authData = useMemo(
() => ({
auth,
login,
logout,
}),
[auth]
);
if (auth === undefined) return null;
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (!appIsReady) {
return null;
}
return (
<View onLayout={onLayoutRootView}>
<AuthContext.Provider value={authData}>
<PaperProvider>{auth ? <AppNavigation /> : <Auth />}</PaperProvider>
</AuthContext.Provider>
</View>
);
}
So I have an azure sql database and I got the register to work and add fields to the sql database just fine using node.js and react as my front end. I'm trying to get my login to work and I set it up the same and same on the frontend just like my register, but it keeps returning wrong username or password when it is correct. Could anyone help and tell me what I'm doing wrong?
const express = require("express");
const cors = require("cors");
const app = express();
app.use(express.json({
type: ['application/json', 'text/plain']
}));
app.use(cors());
const { Connection, Request, TYPES } = require("tedious");
// Create connection to database
const config = {
authentication: {
options: {
userName: "username", // update me
password: "password" // update me
},
type: "default"
},
server: "server.database.windows.net", // update me
options: {
database: "server", //update me
encrypt: true
}
};
const connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on("connect", err => {
if (err) {
console.error(err.message);
} else {
console.log("Server Running and Connected")
}
});
app.post("/register", (req, res)=> {
var sql = "INSERT dbo.userinfo(first_name, last_name, user_name, password, email) VALUES (#firstname, #lastname, #username, #password, #email)"
// Read all rows from table
const request = new Request(sql,
(err, result) => {
if (err) {
console.error(err.message);
} else {
console.log('worked');
}
}
);
request.addParameter('firstname', TYPES.NVarChar, req.body.firstname)
request.addParameter('lastname', TYPES.NVarChar, req.body.lastname)
request.addParameter('username', TYPES.NVarChar, req.body.username)
request.addParameter('password', TYPES.NVarChar,req.body.password)
request.addParameter('email', TYPES.NVarChar, req.body.email)
connection.execSql(request);
})
app.post('/login', (req, res)=>{
var sql = "SELECT * FROM dbo.userinfo WHERE user_name = #username AND password = #password"
const request = new Request(sql,
(err, result) => {
if (err) {
res.send({err: err})
}
if(result > 0){
res.send(result)
console.log("passed")
}
else{
res.send({message: "Wrong username/password combination"})
}
}
);
request.addParameter('username', TYPES.NVarChar, req.body.usernamelog)
request.addParameter('password', TYPES.NVarChar,req.body.passwordlog)
connection.execSql(request);
})
connection.connect();
app.listen(1433, () => {
console.log("running server");
});
FrontEnd
import React, {useState} from 'react';
import Axios from 'axios'
import { StyleSheet, Text, View, SafeAreaView, Modal, Button, TextInput } from 'react-native';
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
const [modalVisible2, setModalVisible2] = useState(false);
const [firstnamereg, setfirstname] = useState('')
const [lastnamereg, setlastname] = useState('')
const [emailreg, setemail] = useState('')
const [usernamereg, setusername] = useState('')
const [passwordreg, setpassword] = useState('')
const [usernamelog, setusernamelog] = useState('')
const [passwordlog, setpasswordlog] = useState('')
const register = () => {
Axios.post('http://localhost:1433/register', {
firstname: firstnamereg,
lastname: lastnamereg,
username: usernamereg,
password: passwordreg,
email: emailreg,
}).then((response) => {
console.log(response);
});
};
const login = () => {
Axios.post('http://localhost:1433/login', {
username: usernamelog,
password: passwordlog,
}).then((response) => {
console.log(response);
});
};
<View>
<Text style={[styles.title]}>
Login to Account
</Text>
<TextInput
style={styles.input}
placeholder="Username"
keyboardType="string"
onChangeText={setusernamelog}
/>
<TextInput
style={styles.input}
placeholder="Password"
keyboardType="string"
onChangeText={setpasswordlog}
/>
<Button
title='Login'
onPress={login}
/>
enter image description here
I think you can simply check with the result parameter, instead of result.length
Example
app.post('/login', (req, res)=>{
var sql = "SELECT * FROM dbo.userinfo WHERE user_name = #username AND password = #password"
const request = new Request(sql,
(err, result) => {
if (err) {
res.send({err: err})
}
if(result > 0){
res.send(result)
console.log("passed")
}
else{
res.send({message: "Wrong username/password combination"})
}
}
);
request.addParameter('username', TYPES.NVarChar, req.body.username)
request.addParameter('password', TYPES.NVarChar,req.body.password)
connection.execSql(request);
})
Edit: Since in your frontend, you are passing the values as username and password in your post request. So in your backend, you must access it through req.body.username and req.body.password.
I'm developing a react-native application, which uses webRTC.
I extremely liked the minimal version I found here (kudos to baconcheese113!) and I decided to refactor it to create my react component.
I have set up a backend (DynamoDB, Appsync) and a redux store that allows me to:
dispatch an action sendCreateUserControlMsg, which down the line calls the Appsync endpoint to create a new ControlUserMsg
subscribe to a ControlUserMsg, set the flag triggerWebrtcData and save webrtcData in the Redux state
The following component (which for now calls itself), sometimes works, but mostly doesn't. I feel that the problem is related to JS Promises, but I do not fully understand how I should design the component to avoid race conditions.
import React, { useState, useEffect } from 'react';
import { View, SafeAreaView, Button, StyleSheet } from 'react-native';
import { RTCPeerConnection, RTCView, mediaDevices } from 'react-native-webrtc';
import { sendCreateUserControlMsg } from '../redux/actions/UserControlMsgActions';
import controlMsgActions from './../model/control_msg_actions';
import webrtcActionTypes from './../model/webrtc_action_types';
import { useDispatch, useSelector } from "react-redux";
import * as triggersMatch from '../redux/actions/TriggersMatchActions';
var IS_LOCAL_USER = true //manual flag I temporarily set
var localUserID = '00';
var localUser = 'localUser'
var remoteUserID = '01';
var remoteUser = 'remoteUser'
if (IS_LOCAL_USER) {
var matchedUserId = remoteUserID
var user_id = localUserID;
var user = localUser
}
else {
var matchedUserId = localUserID
var user_id = remoteUserID;
var user = remoteUser
}
export default function App() {
const dispatch = useDispatch();
var triggersMatchBool = useSelector(state => state.triggers_match)
var webrtcData = useSelector(state => state.webrtc_description.webrtcData)
const [localStream, setLocalStream] = useState();
const [remoteStream, setRemoteStream] = useState();
const [cachedLocalPC, setCachedLocalPC] = useState();
const [cachedRemotePC, setCachedRemotePC] = useState();
const sendICE = (candidate, isLocal) => {
var type
isLocal ? type = webrtcActionTypes["NEW_ICE_CANDIDATE_FROM_LOCAL"] : type = webrtcActionTypes["NEW_ICE_CANDIDATE_FROM_REMOTE"]
var payload = JSON.stringify({
type,
candidate
})
console.log(`Sending ICE to ${matchedUserId}`)
dispatch(sendCreateUserControlMsg(matchedUserId, user_id, user, payload, controlMsgActions["WEBRTC_DATA"]));
}
const sendOffer = (offer) => {
type = webrtcActionTypes["OFFER"]
var payload = JSON.stringify({
type,
offer
})
console.log(`Sending Offer to ${matchedUserId}`)
dispatch(sendCreateUserControlMsg(matchedUserId, user_id, user, payload, controlMsgActions["WEBRTC_DATA"]));
}
const sendAnswer = (answer) => {
type = webrtcActionTypes["ANSWER"]
var payload = JSON.stringify({
type,
answer
})
console.log(`Sending answer to ${matchedUserId}`)
dispatch(sendCreateUserControlMsg(matchedUserId, user_id, user, payload, controlMsgActions["WEBRTC_DATA"]));
}
const [isMuted, setIsMuted] = useState(false);
// START triggers
async function triggerMatchWatcher() {
if (triggersMatchBool.triggerWebrtcData) {
dispatch(triggersMatch.endTriggerWebrtcData());
switch (webrtcData.type) {
case webrtcActionTypes["NEW_ICE_CANDIDATE_FROM_LOCAL"]:
try {
setCachedRemotePC(cachedRemotePC.addIceCandidate(webrtcData.candidate))
} catch (error) {
console.warn('ICE not added')
}
break;
case webrtcActionTypes["NEW_ICE_CANDIDATE_FROM_REMOTE"]:
try {
setCachedLocalPC(cachedLocalPC.addIceCandidate(webrtcData.candidate))
} catch (error) {
console.warn('ICE not added')
}
break;
case webrtcActionTypes["OFFER"]:
console.log('remotePC, setRemoteDescription');
try {
await cachedRemotePC.setRemoteDescription(webrtcData.offer);
console.log('RemotePC, createAnswer');
const answer = await cachedRemotePC.createAnswer();
setCachedRemotePC(cachedRemotePC)
sendAnswer(answer);
} catch (error) {
console.warn(`setRemoteDescription failed ${error}`);
}
case webrtcActionTypes["ANSWER"]:
try {
console.log(`Answer from remotePC: ${webrtcData.answer.sdp}`);
console.log('remotePC, setLocalDescription');
await cachedRemotePC.setLocalDescription(webrtcData.answer);
setCachedRemotePC(cachedRemotePC)
console.log('localPC, setRemoteDescription');
await cachedLocalPC.setRemoteDescription(cachedRemotePC.localDescription);
setCachedLocalPC(cachedLocalPC)
} catch (error) {
console.warn(`setLocalDescription failed ${error}`);
}
}
}
}
useEffect(() => {
triggerMatchWatcher()
}
);
const startLocalStream = async () => {
// isFront will determine if the initial camera should face user or environment
const isFront = true;
const devices = await mediaDevices.enumerateDevices();
const facing = isFront ? 'front' : 'environment';
const videoSourceId = devices.find(device => device.kind === 'videoinput' && device.facing === facing);
const facingMode = isFront ? 'user' : 'environment';
const constraints = {
audio: true,
video: {
mandatory: {
minWidth: 500, // Provide your own width, height and frame rate here
minHeight: 300,
minFrameRate: 30,
},
facingMode,
optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
},
};
const newStream = await mediaDevices.getUserMedia(constraints);
setLocalStream(newStream);
};
const startCall = async () => {
const configuration = { iceServers: [{ url: 'stun:stun.l.google.com:19302' }] };
const localPC = new RTCPeerConnection(configuration);
const remotePC = new RTCPeerConnection(configuration);
localPC.onicecandidate = e => {
try {
console.log('localPC icecandidate:', e.candidate);
if (e.candidate) {
sendICE(e.candidate, true)
}
} catch (err) {
console.error(`Error adding remotePC iceCandidate: ${err}`);
}
};
remotePC.onicecandidate = e => {
try {
console.log('remotePC icecandidate:', e.candidate);
if (e.candidate) {
sendICE(e.candidate, false)
}
} catch (err) {
console.error(`Error adding localPC iceCandidate: ${err}`);
}
};
remotePC.onaddstream = e => {
console.log('remotePC tracking with ', e);
if (e.stream && remoteStream !== e.stream) {
console.log('RemotePC received the stream', e.stream);
setRemoteStream(e.stream);
}
};
localPC.addStream(localStream);
// Not sure whether onnegotiationneeded is needed
// localPC.onnegotiationneeded = async () => {
// try {
// const offer = await localPC.createOffer();
// console.log('Offer from localPC, setLocalDescription');
// await localPC.setLocalDescription(offer);
// sendOffer(localPC.localDescription)
// } catch (err) {
// console.error(err);
// }
// };
try {
const offer = await localPC.createOffer();
console.log('Offer from localPC, setLocalDescription');
await localPC.setLocalDescription(offer);
sendOffer(localPC.localDescription)
} catch (err) {
console.error(err);
}
setCachedLocalPC(localPC);
setCachedRemotePC(remotePC);
};
const switchCamera = () => {
localStream.getVideoTracks().forEach(track => track._switchCamera());
};
const closeStreams = () => {
if (cachedLocalPC) {
cachedLocalPC.removeStream(localStream);
cachedLocalPC.close();
})
}
if (cachedRemotePC) {
cachedRemotePC.removeStream(localStream);
cachedRemotePC.close();
})
}
setLocalStream();
setRemoteStream();
setCachedRemotePC();
setCachedLocalPC();
};
return (
<SafeAreaView style={styles.container}>
{!localStream && <Button title="Click to start stream" onPress={startLocalStream} />}
{localStream && <Button title="Click to start call" onPress={startCall} disabled={!!remoteStream} />}
{localStream && (
<View style={styles.toggleButtons}>
<Button title="Switch camera" onPress={switchCamera} />
</View>
)}
<View style={styles.rtcview}>
{localStream && <RTCView style={styles.rtc} streamURL={localStream.toURL()} />}
</View>
<View style={styles.rtcview}>
{remoteStream && <RTCView style={styles.rtc} streamURL={remoteStream.toURL()} />}
</View>
<Button title="Click to stop call" onPress={closeStreams} disabled={!remoteStream} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
// omitted
});
The most common errors I receive are:
Error: Failed to add ICE candidate
Possible Unhandled Promise Rejection
and
setLocalDescription failed TypeError: Cannot read property 'sdp' of
undefined
If I console.log I can see that are JS Promise, but since are not a functions I cannot use .then().
How can I call the addIceCandidate method or setLocalDescription method without incurring in the Unhandled Promise Rejection errors?
What are the best practices to work with WebRTC in react-native?