I'm building a project using react native and webRTC with nodejs + ejs.
establish connections:
1- browser to browser works well.
2- device to browser works well.
3- browser to device does not work and here is the problem and all codes are the same for socket io and peer connections.
// REACT NATIVE PART
const [localStream, setLocalStream] = useState<MediaStream|null>(null);
const [remoteStream, setRemoteStream] = useState<MediaStream|null>(null);
const socket = io(utils.RAW_BACKEND_URL)
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: ['stun:stun.l.google.com:19302']
}
]
})
useEffect(()=> {
peerConnection.onaddstream = (e) => {
setRemoteStream(e.stream);
}
socket.emit('join-room')
socket.on('calling-user', async (args)=> {
setOffer(JSON.stringify(args.offer))
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.offer));
utils.showAlertMessage("Calling", "You have a call", [
{
text: "Call?",
onPress: async ()=> await answerCall()
},
{
text: "No",
}
])
})
socket.on('ic-candidate', async(args)=> {
await peerConnection.addIceCandidate(new RTCIceCandidate(args.candidate))
})
socket.on('answer-made', async (args)=> {
console.log("HERE");
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer));
setShow(true)
})
}, [])
const getUserMedia = async (callAUser?:boolean) => {
let isFront = true, videoSourceId: any = null;
try {
const availableDevices = await mediaDevices.enumerateDevices();
let videoSourceId;
for (let i = 0; i < availableDevices.length; i++) {
const sourceInfo = availableDevices[i];
if (
sourceInfo.kind == 'videoinput' &&
sourceInfo.facing == (isFront ? 'front' : 'environment')
) {
videoSourceId = sourceInfo.deviceId;
}
}
const mediaStream = await mediaDevices.getUserMedia({
// audio: true,
video: {
mandatory: {
minWidth: 500,
minHeight: 300,
minFrameRate: 30,
},
facingMode: 'user',
optional: [{sourceId: videoSourceId}]
}
})
setLocalStream(mediaStream);
peerConnection.addStream(mediaStream);
if(callAUser){
await callUser();
}
}catch(err: any) {
utils.showAlertMessage("ERRORsss", err.message);
}
}
const callUser = async () => {
peerConnection.onicecandidate = e => {
if(e.candidate) {
socket.emit('candidate', {
candidate: e.candidate
})
}
}
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(new RTCSessionDescription(offer));
socket.emit('call-user', {
offer: offer
})
}
const answerCall = async () => {
await getUserMedia();
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(new RTCSessionDescription(answer));
socket.emit('make-answer', {
answer
})
}
return (
<View style={styles.stream}>
<Button title="Call" onPress={()=>getUserMedia(true)} />
<Button title="Answer" onPress={()=>answerCall()} />
{localStream != null &&
<RTCView
objectFit={"cover"}
streamURL={localStream.toURL()}
style={{height: '50%', borderWidth: 1, borderColor: 'red'}}
/>
}
{remoteStream != null && show ?
<RTCView
objectFit={"cover"}
streamURL={remoteStream.toURL()}
style={{height: '50%', borderWidth: 1, borderColor: 'blue'}}
/>
: <Text>{offer}</Text>
}
</View>
);
//js file for serving ejs page
const client = io("https://b277-2001-16a2-cb25-a800-f1da-b62e-7f94-42ee.ngrok.io");
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: ['stun:stun.l.google.com:19302']
}
]
})
client.on('answer-made', async (args)=> {
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer));
sdpAnswer.innerHTML = JSON.stringify(args.answer);
})
client.on('answer-made', async (args)=> {
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer));
sdpAnswer.innerHTML = JSON.stringify(args.answer);
})
onst callUser = async () => {
await getMedia();
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(new RTCSessionDescription(offer));
peerConnection.onicecandidate = (e) => {
if(e.candidate) {
client.emit('candidate', {
candidate: e.candidate
})
}
}
client.emit('call-user', {
offer
})
}
// socket io part
client.join("q2");
client.on('join-room', (args)=> {
client.broadcast.to("q2").emit("user-joined", {
id: client.id
})
})
client.on("call-user", (args) => {
client.broadcast.to("q2").emit("calling-user", args);
});
client.on("make-answer", (args) => {
client.broadcast.to("q2").emit("answer-made", args);
});
client.on("candidate", (args) => {
client.broadcast.to("q2").emit("ic-candidate", args);
});
I hope you can help me what mistake I made and did not figure it.
Thanks in advance
I am a beginner in the MERN stack and I am interested in why I have to refresh the page after deleting the document (post)?
This is my Action.js
export const deletePost = id => async (dispatch, getState) => {
try {
dispatch({ type: DELETE_POST_BEGIN });
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.delete(`/api/v1/post/${id}`, config);
dispatch({ type: DELETE_POST_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: DELETE_POST_FAIL,
payload: { msg: error.response.data.msg },
});
}
};
This is my Reducer.js
export const deletePostReducer = (state = {}, action) => {
switch (action.type) {
case DELETE_POST_BEGIN:
return { loading: true };
case DELETE_POST_SUCCESS:
return { loading: false };
case DELETE_POST_FAIL:
return { loading: false, error: action.payload.msg };
default:
return state;
}
};
And this is my Home page where i list all posts:
import { useEffect } from 'react';
import { Col, Container, Row } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../actions/postActions';
import Loader from '../components/Loader';
import Message from '../components/Message';
import Post from '../components/Post';
const HomePage = () => {
const dispatch = useDispatch();
const allPosts = useSelector(state => state.getPosts);
const { loading, error, posts } = allPosts;
const deletePost = useSelector(state => state.deletePost);
const { loading: loadingDelete } = deletePost;
useEffect(() => {
dispatch(getPosts());
}, [dispatch]);
return (
<Container>
{loading || loadingDelete ? (
<Loader />
) : error ? (
<Message variant='danger'>{error}</Message>
) : (
<>
<Row>
{posts.map(post => (
<Col lg={4} key={post._id} className='mb-3'>
<Post post={post} />
</Col>
))}
</Row>
</>
)}
</Container>
);
};
export default HomePage;
And this is my single Post component:
const Post = ({ post }) => {
const dispatch = useDispatch();
const allPosts = useSelector(state => state.getPosts);
const { loading, error, posts } = allPosts;
const userLogin = useSelector(state => state.userLogin);
const { userInfo } = userLogin;
const handleDelete = id => {
dispatch(deletePost(id));
};
return (
<>
<div>{post.author.username}</div>
<Card>
<Card.Img variant='top' />
<Card.Body>
<Card.Title>{post.title}</Card.Title>
<Card.Text>{post.content}</Card.Text>
<Button variant='primary'>Read more</Button>
{userInfo?.user._id == post.author._id && (
<Button variant='danger' onClick={() => handleDelete(post._id)}>
Delete
</Button>
)}
</Card.Body>
</Card>
</>
);
};
And my controller:
const deletePost = async (req, res) => {
const postId = req.params.id;
const post = await Post.findOne({ _id: postId });
if (!post.author.equals(req.user.userId)) {
throw new BadRequestError('You have no permission to do that');
}
await Post.deleteOne(post);
res.status(StatusCodes.NO_CONTENT).json({
post,
});
};
I wish someone could help me solve this problem, it is certainly something simple but I am a beginner and I am trying to understand.
I believe the issue is that you are not fetching the posts after delete is successful.
Try this inside the HomePage component:
...
const [isDeleting, setIsDeleting] = useState(false);
const { loading: loadingDelete, error: deleteError } = deletePost;
useEffect(() => {
dispatch(getPosts());
}, [dispatch]);
useEffect(() => {
if (!deleteError && isDeleting && !loadingDelete) {
dispatch(getPosts());
}
setIsDeleting(loadingDelete);
}, [dispatch, deleteError, isDeleting, loadingDelete]);
...
Another method is to use "filtering", but you have to update your reducer as such:
export const deletePostReducer = (state = {}, action) => {
switch (action.type) {
case DELETE_POST_BEGIN:
return { loading: true };
case DELETE_POST_SUCCESS:
return { loading: false, data: action.payload}; // <-- this was changed
case DELETE_POST_FAIL:
return { loading: false, error: action.payload.msg };
default:
return state;
}
};
Now in your HomePage component, you will do something like this when rendering:
...
const { loading: loadingDelete, data: deletedPost } = deletePost;
...
useEffect(() => {
dispatch(getPosts());
if (deletedPost) {
console.log(deletedPost);
}
}, [dispatch, deletedPost]);
return (
...
<Row>
{posts.filter(post => post._id !== deletedPost?._id).map(post => (
<Col lg={4} key={post._id} className='mb-3'>
<Post post={post} />
</Col>
))}
</Row>
)
I want to implement conference video call in React-native and node js using without any paid library
I was Implement single Person Video call using react-native-webrtc and node js Socket using Peer-to-Peer
My React-Native files below
My Privider Files
import React, { useState } from "react";
import { Alert } from "react-native";
import {
mediaDevices,
MediaStream,
MediaStreamConstraints,
} from "react-native-webrtc";
import socketio from "socket.io-client";
import ReactNativeForegroundService from "#supersami/rn-foreground-service";
import { MainContext as MainContextType, User } from "../interfaces";
import {
SERVER_URL,
PEER_SERVER_HOST,
PEER_SERVER_PORT,
PEER_SERVER_PATH,
} from "../server";
// #ts-ignore
import Peer from "react-native-peerjs";
import { navigate } from "../helpers/RootNavigation";
import InCallManager from "react-native-incall-manager";
const initialValues: MainContextType = {
username: "",
peerId: "",
users: [],
localStream: null,
remoteStream: null,
remoteUser: null,
initialize: () => {},
setUsername: () => {},
call: () => {},
switchCamera: () => {},
toggleMute: () => {},
isMuted: false,
isShareScreen: false,
toggleSpeacker: () => {},
isSpeaker: true,
swipeWindow: false,
closeCall: () => {},
reset: () => {},
localStreamSet: () => {},
activeCall: null,
};
export const MainContext = React.createContext(initialValues);
interface Props {}
const MainContextProvider: React.FC<Props> = ({ children }) => {
const [username, setUsername] = useState(initialValues.username);
const [peerId, setPeerId] = useState(initialValues.peerId);
const [users, setUsers] = useState<User[]>(initialValues.users);
const [localStream, setLocalStream] = useState<MediaStream | null>(
initialValues.localStream
);
const [remoteStream, setRemoteStream] = useState<MediaStream | null>(
initialValues.remoteStream
);
const [remoteUser, setRemoteUser] = useState<User | null>(null);
const [socket, setSocket] = useState<SocketIOClient.Socket | null>(null);
const [peerServer, setPeerServer] = useState<any>(null);
const [isMuted, setIsMuted] = useState(initialValues.isMuted);
const [swipeWindow, setSwipeWindow] = useState(initialValues.swipeWindow);
const [isShareScreen, setIsShareScreen] = useState(
initialValues.isShareScreen
);
// const localStreamSet=(newstream)=>{
// setLocalStream(null)
// }
const [isSpeaker, setIsSpeaker] = useState(initialValues.isSpeaker);
const [activeCall, setActiveCall] = useState<any>(null);
const initialize = async () => {
const isFrontCamera = true;
const devices = await mediaDevices.enumerateDevices();
const facing = isFrontCamera ? "front" : "environment";
const videoSourceId = devices.find(
(device: any) => device.kind === "videoinput" && device.facing === facing
);
const facingMode = isFrontCamera ? "user" : "environment";
const constraints: MediaStreamConstraints = {
audio: true,
video: {
mandatory: {
minWidth: 1280,
minHeight: 720,
minFrameRate: 30,
},
facingMode,
optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
},
};
const newStream = await mediaDevices.getUserMedia(constraints);
setLocalStream(newStream as MediaStream);
const io = socketio.connect(SERVER_URL, {
reconnection: true,
autoConnect: true,
});
io.on("connect", () => {
setSocket(io);
io.emit("register", username);
});
io.on("users-change", (users: User[]) => {
setUsers(users);
});
io.on("accepted-call", (user: User) => {
InCallManager.start("video");
setRemoteUser(user);
});
io.on("rejected-call", (user: User) => {
InCallManager.stop();
InCallManager.start();
setRemoteUser(null);
setActiveCall(null);
Alert.alert("Your call request rejected by " + user?.username);
navigate("Users");
});
io.on("not-available", (username: string) => {
setRemoteUser(null);
setActiveCall(null);
Alert.alert(username + " is not available right now");
navigate("Users");
});
const peerServer = new Peer(undefined, {
host: PEER_SERVER_HOST,
path: PEER_SERVER_PATH,
secure: true,
port: PEER_SERVER_PORT,
config: {
iceServers: [
{
urls: [
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
],
},
],
},
});
peerServer.on("error", (err: Error) =>
);
peerServer.on("open", (peerId: string) => {
setPeerServer(peerServer);
setPeerId(peerId);
io.emit("set-peer-id", peerId);
});
io.on("call", (user: User) => {
peerServer.on("call", (call: any) => {
InCallManager.startRingtone("_BUNDLE_");
setRemoteUser(user);
Alert.alert(
"New Call",
"You have a new call from " + user?.username,
[
{
text: "Reject",
onPress: () => {
InCallManager.stopRingtone();
InCallManager.stop();
io.emit("reject-call", user?.username);
setRemoteUser(null);
setActiveCall(null);
},
style: "cancel",
},
{
text: "Accept",
onPress: () => {
InCallManager.stopRingtone();
InCallManager.start();
InCallManager.setSpeakerphoneOn(true);
io.emit("accept-call", user?.username);
call.answer(newStream);
setActiveCall(call);
navigate("Call");
},
},
],
{ cancelable: false }
);
call.on("stream", (stream: MediaStream) => {
setRemoteStream(stream);
});
call.on("close", () => {
closeCall();
});
call.on("error", () => {});
});
});
};
const call = (user: User) => {
if (!peerServer || !socket) {
Alert.alert("Peer server or socket connection not found");
return;
}
if (!user.peerId) {
Alert.alert("User not connected to peer server");
return;
}
socket.emit("call", user.username);
setRemoteUser(user);
try {
const call = peerServer.call(user.peerId, localStream);
call.on(
"stream",
(stream: MediaStream) => {
setActiveCall(call);
setRemoteStream(stream);
},
(err: Error) => {
console.error("Failed to get call stream", err);
}
);
} catch (error) {
}
};
const switchCamera = () => {
if (localStream) {
// #ts-ignore
localStream.getVideoTracks().forEach((track) => track._switchCamera());
}
};
const toggleMute = () => {
if (localStream)
localStream.getAudioTracks().forEach((track) => {
track.enabled = !track.enabled;
setIsMuted(!track.enabled);
});
};
const toggleswipeWindow = () => {
var templocalstream = localStream;
var tempremotestream = remoteStream;
if (swipeWindow == false) {
setLocalStream(tempremotestream);
setRemoteStream(templocalstream);
setSwipeWindow(!swipeWindow);
} else {
setLocalStream(tempremotestream);
setRemoteStream(templocalstream);
setSwipeWindow(!swipeWindow);
}
};
const toggleScreenShare = async () => {
if (localStream)
if (isShareScreen == false) {
mediaDevices
.getDisplayMedia({ video: true, audio: true })
.then(handleSuccess, handleError);
InCallManager.setKeepScreenOn(true);
setIsShareScreen(true);
} else {
// localStream.getVideoTracks().forEach((track) => {track.stop()}
ReactNativeForegroundService.stop();
InCallManager.setKeepScreenOn(false);
setIsShareScreen(false);
}
};
const toggleSpeacker = () => {
if (localStream) InCallManager.start();
InCallManager.setSpeakerphoneOn(!isSpeaker);
setIsSpeaker(!isSpeaker);
};
const closeCall = () => {
activeCall?.close();
setActiveCall(null);
setRemoteUser(null);
navigate("Users");
Alert.alert("Call is ended");
};
const reset = async () => {
peerServer?.destroy();
socket?.disconnect();
setActiveCall(null);
setRemoteUser(null);
setLocalStream(null);
setRemoteStream(null);
setUsername("");
setPeerId("");
};
const handleError = async (error) => {
};
const handleSuccess = async (stream) => {
localStream.getVideoTracks().forEach((track) => {
localStream.removeTrack(track);
});
localStream.addTrack(stream.getTracks()[0]);
if (swipeWindow == true) {
setRemoteStream(stream);
} else {
setLocalStream(stream);
}
stream.getVideoTracks()[0].addEventListener("ended", () => {
});
};
return (
<MainContext.Provider
value={{
username,
setUsername,
peerId,
setPeerId,
users,
setUsers,
localStream,
setLocalStream,
remoteStream,
setRemoteStream,
initialize,
call,
switchCamera,
toggleMute,
isMuted,
isSpeaker,
toggleSpeacker,
closeCall,
reset,
remoteUser,
activeCall,
toggleScreenShare,
isShareScreen,
toggleswipeWindow,
swipeWindow,
// localStreamSet
}}
>
{children}
</MainContext.Provider>
);
};
export default MainContextProvider;
Callscreen.js File
import React, {useContext} from 'react';
import {
ActivityIndicator,
Dimensions,
StyleSheet,
Text,
View,
TouchableWithoutFeedback,
TouchableHighlight
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {RTCView} from 'react-native-webrtc';
import IconButton from '../components/IconButton';
import icons from '../constants/icons';
import {CallScreenNavigationProp} from '../interfaces/navigation';
import {MainContext} from '../store/MainProvider';
import InCallManager from 'react-native-incall-manager';
const {width, height} = Dimensions.get('window');
import RecordScreen from 'react-native-record-screen';
import Video from 'react-native-video';
interface Props {
navigation: CallScreenNavigationProp;
}
const Call = ({}: Props) => {
const {
localStream,
remoteStream,
activeCall,
remoteUser,
isMuted,
isSpeaker,
toggleSpeacker,
toggleScreenShare,
isShareScreen,
closeCall,
toggleMute,
switchCamera,
swipeWindow,
toggleswipeWindow
} = useContext(MainContext);
React.useEffect(() => {
if (InCallManager.recordPermission !== 'granted') {
InCallManager.requestRecordPermission()
.then((requestedRecordPermissionResult) => {
})
.catch((err) => {
});
}
});
const [recordscreen,setRecordScreen]=React.useState(false)
const btnStyle = React.useMemo(() => {
return recordscreen ? styles.btnActive : styles.btnDefault;
}, [recordscreen]);
const [uri, setUri] = React.useState('');
const _handleOnRecording = async () => {
if (recordscreen) {
setRecordScreen(false);
const res = await RecordScreen.stopRecording().catch((error) =>
console.warn(error)
);
if (res) {
setUri(res.result.outputURL);
}
} else {
setUri('');
setRecordScreen(true);
await RecordScreen.startRecording().catch((error) => {
console.warn(error);
setRecordScreen(false);
setUri('');
});
}
};
return (
<SafeAreaView style={styles.container}>
{uri ? (
<View style={styles.preview}>
<Video
source={{
uri,
}}
style={styles.video}
/>
</View>
) : null}
{remoteStream && (
<RTCView
key={2}
mirror={true}
style={styles.remoteStream}
streamURL={remoteStream.toURL()}
objectFit="cover"
/>
)}
{localStream && (
<View style={styles.myStreamWrapper}>
<TouchableWithoutFeedback onPress={toggleswipeWindow}>
<RTCView
style={styles.myStream}
objectFit="cover"
streamURL={localStream.toURL()}
zOrder={1}
/>
</TouchableWithoutFeedback>
</View>
)}
{!activeCall && (
<View style={styles.spinnerWrapper}>
<ActivityIndicator color="#341EFF" size={120} />
<Text style={styles.callingText}>Calling {remoteUser?.username}</Text>
</View>
)}
<View style={styles.iconsWrapper}>
<IconButton
icon={icons.CHANGE_CAMERA}
onPress={switchCamera}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
{isMuted ? (
<IconButton
icon={icons.UNMUTE}
onPress={toggleMute}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.MUTE}
onPress={toggleMute}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{isSpeaker ? (
<IconButton
icon={icons.SPEAKERON}
onPress={toggleSpeacker}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
) : (
<IconButton
icon={icons.SPEAKEROFF}
onPress={toggleSpeacker}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{recordscreen ? (
<IconButton
icon={icons.RECORDING}
onPress={_handleOnRecording}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.RECORDING}
onPress={_handleOnRecording}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{isShareScreen ? (
<IconButton
icon={icons.SCREENSHARE}
onPress={toggleScreenShare}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.SCREENSHARE}
onPress={toggleScreenShare}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
<IconButton
icon={icons.END_CALL}
onPress={closeCall}
iconColor={'#fff'}
backgroundColor="red"
/>
</View>
</SafeAreaView>
);
};
export default Call;
const styles = StyleSheet.create({
preview: {
position: 'absolute',
right: 12,
bottom: 116,
width: Dimensions.get('window').width / 2,
height: Dimensions.get('window').height / 3,
zIndex: 1,
padding: 8,
backgroundColor: '#aaa',
},
video: {
flex: 1,
},
container: {
backgroundColor: '#0f0f0f',
flex: 1,
position: 'relative',
},
btnDefault: {
width: 48,
height: 48,
backgroundColor: '#fff',
borderRadius: 24,
borderWidth: 4,
borderStyle: 'solid',
borderColor: '#212121',
},
btnActive: {
width: 36,
height: 36,
backgroundColor: 'red',
borderRadius: 8,
},
myStream: {
height: width * 0.6,
width: width * 0.4,
},
myStreamWrapper: {
position: 'absolute',
bottom: 20,
right: 20,
height: width * 0.6 + 8,
width: width * 0.4 + 8,
backgroundColor: '#333',
borderRadius: 12,
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'center',
},
remoteStreamWrapper: {},
remoteStream: {
width: '100%',
height: '100%',
},
spinnerWrapper: {
top: height * 0.3,
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
callingText: {
fontSize: 26,
color: '#fff',
},
iconsWrapper: {
position: 'absolute',
bottom: 20,
left: 20,
},
});
Socket Server.js
//socketio
const socketio = require("socket.io");
class SocketService {
io;
constructor() {
this.io = null;
}
listen = (server) => {
this.io = socketio(server);
this.io.users = {};
this.io.on("connection", (socket) => {
socket.on("register", (username) => this.onRegister(socket, username));
socket.on("set-peer-id", (peerId) => this.onSetPeerId(socket, peerId));
socket.on("call", (username) => this.onCall(socket, username));
socket.on("reject-call", (username) =>
this.onRejectCall(socket, username)
);
socket.on("accept-call", (username) =>
this.onAcceptCall(socket, username)
);
console.log(`${Date(Date.now()).toLocaleString()}: new user connected`);
socket.on("disconnect", () => this.onDisconnect(socket));
});
};
onAcceptCall = (socket, username) => {
if (this.io.users[username])
this.io
.to(this.io.users[username].socketId)
.emit("accepted-call", this.io.users[socket.username]);
};
onRejectCall = (socket, username) => {
if (this.io.users[username]) {
this.io
.to(this.io.users[username].socketId)
.emit("rejected-call", this.io.users[socket.username]);
}
};
onCall = (socket, username) => {
if (this.io.users[username]) {
this.io
.to(this.io.users[username].socketId)
.emit("call", this.io.users[socket.username]);
} else {
socket.emit("not-available", username);
}
};
onRegister = (socket, username) => {
console.log("Registered", username);
socket.username = username;
this.io.users[username] = {
username,
peerId: "",
socketId: socket.id,
};
this.onUsersChange(socket);
};
getUsers = () => {
const users = [];
Object.keys(this.io.users).forEach((key) => {
users.push(this.io.users[key]);
});
return users;
};
onUsersChange = (socket) => {
this.io.emit("users-change", this.getUsers());
};
onSetPeerId = (socket, peerId) => {
console.log("Set Peer Id user:", socket.username, " peerId: ", peerId);
this.io.users[socket.username] = {
peerId,
socketId: socket.id,
username: socket.username,
};
this.onUsersChange();
};
onDisconnect = (socket) => {
delete this.io.users[socket.username];
console.log(
`${Date(Date.now()).toLocaleString()} ID:${
socket.username
} user disconnected`
);
this.onUsersChange();
};
emit = (event, userId, data) => {
if (this.io.users[userId]) {
this.io.to(this.io.users[userId]).emit(event, data);
}
};
}
module.exports = new SocketService();
Peer Server.js (2nd API server in Node js)
require('dotenv').config()
const express = require("express");
const { ExpressPeerServer } = require("peer");
const app = express();
app.get("/", (req, res, next) => res.send("Hello world!"));
const http = require("http");
const server = http.createServer(app);
const peerServer = ExpressPeerServer(server, {
debug: true,
path: "/",
});
app.use("/peerjs", peerServer);
server.listen(process.env.PORT || 9000);
I'm sourcing the image on aws and when I run the code through i get warning error that source.uri is null and the image wont display. Im getting the image from the server cause i can see the image in the debugger but it wont display in the code.
This is my action file src/actions/item.js
import { HOST } from '../constants';
import { normalizeItems, normalizeItem } from '../utils';
export const SET_ITEMS = 'SET_ITEMS';
export function setItems(items) {
return {
type: SET_ITEMS,
items
}
}
export function getItems() {
return (dispatch, getState) => {
return fetch(`${HOST}/api/v1/items`)
.then(response => response.json())
.then(json => {
console.log("getItems", json);
if (json.is_success) {
dispatch(setItems(normalizeItems(json.items)));
} else {
alert(json.error);
}
})
.catch(e => alert(e));
}
}
This the image of the debugger shows the i have the image there
This is my reducers file src/reducers/item.js
import { SET_ITEMS,SET_ITEM } from '../actions/item';
const initialState = {
items: [],
};
export default function(state = initialState, action) {
if (action.type === SET_ITEMS) {
return {
...state,
items: action.items
}
}
This file where i render my code src/components/MainScreen/ExploreTab.js
class ExploreTab extends Component {
componentWillMount() {
this.props.getItems();
}
onPress(item) {
this.props.navigate({ routeName: "Item", params: { item: item } });
}
render() {
const { items, filter } = this.props;
return (
<FlatList
style={styles.container}
data = { items }
renderItem={({item}) =>
<TouchableOpacity onPress={() => this.onPress(item)} style={styles.item}>
<Image style={styles.image} source = {{uri: item.image}} />
<Text style = {styles.title}>{`$${item.price} ${item.instant ? '🎉 ' : ''}${item.title}`}</Text>
<Text>{`${item.itemCategory} - ${item.itemCondition} `}</Text>
</TouchableOpacity>
}
keyExtractor={(item, index) => item.id}
/>
);
}
}
const mapStateToProps = state => ({
items: state.item.items
});
const mapDispatchToProps = dispatch => ({
navigate: (route) => dispatch(navigate(route)),
getItems: () => dispatch(getItems()),
});
if I change this line
<Image style={styles.image} source = {{uri: item.image}} />
to this I will see the image
<Image style={styles.image} source = {{uri: 'https://s3.us-east-2.amazonaws.com/borroup/photos/images/1/medium/Screen_Shot_2018-03-22_at_10.48.28_PM.png'}} />
In the src/utils/index.js
I had setup as
import { HOST } from '../constants';
export function normalizeItems(items) {
return items.map(item => {
return{
id: item.id || '',
title: item.item_name ||'',
image: `${HOST}${item.image}` ||'',
itemCategory: item.item_category ||'',
itemCondition: item.item_condition ||'',
price: item.price ||'',
instant: item.instant ||'',
}
})
}
so i had to change
image: `${HOST}${item.image}` ||'',
to this and worked for me
image: `${item.image}` ||'',