I am using web viewer and want to rotate individual pages and update them in the database.
Right now I am able to rotate the whole pdf only.
I am following this doc https://www.pdftron.com/documentation/web/guides/manipulation/rotate/
but not able to understand much
export default function PdfTron(props: any): ReactElement {
const viewer = useRef<HTMLDivElement>(null);
const {DrawingLibDetailsState, DrawingLibDetailsDispatch}: any = useContext(DrawingLibDetailsContext);
const [newInstance, setNewInstance] = useState<any>(null);
const [currentPage, setCurrentPage] = useState<any>(null);
const {dispatch, state }:any = useContext(stateContext);
//console.log("currentPage in state",currentPage)
useEffect(() => {
WebViewer(
{
path: '/webviewer/lib',
licenseKey: process.env["REACT_APP_PDFTRON_LICENSE_KEY"],
initialDoc: '',
filename: 'drawings',
extension: "pdf",
isReadOnly: true,
fullAPI: true,
disabledElements: [
// 'leftPanelButton',
// // 'selectToolButton',
// 'stickyToolButton',
// 'toggleNotesButton',
]
},
viewer.current as HTMLDivElement,
).then((instance: any) => {
setNewInstance(instance)
// you can now call WebViewer APIs here...
});
}, []);
useEffect(() => {
if(DrawingLibDetailsState?.parsedFileUrl?.url && newInstance ){
const s3Key = DrawingLibDetailsState?.parsedFileUrl?.s3Key;
const pageNum = s3Key.split('/')[s3Key.split('/').length-1].split('.')[0];
const fileName = DrawingLibDetailsState?.drawingLibDetails[0]?.fileName?.replace(".pdf", "");
const downloadingFileName = `page${pageNum}_${fileName}`;
newInstance.loadDocument(DrawingLibDetailsState?.parsedFileUrl?.url, {extension: "pdf",
filename: downloadingFileName ? downloadingFileName : 'drawing',})
const { documentViewer } = newInstance.Core;
const pageRotation = newInstance.Core.PageRotation;
const clickDocument =newInstance.Core.DocumentViewer.Click;
const pageNumber = newInstance.Core.pageNum;
//get page rotation from the PDF
documentViewer.addEventListener('rotationUpdated', (rotation: number) => {
updateRotation(rotation)
})
// trigger an event after the document loaded
documentViewer.addEventListener('documentLoaded', async() => {
const doc = documentViewer.getDocument();
const rotation = DrawingLibDetailsState?.drawingLibDetails[0]?.sheetsReviewed?.pdfRotation ?
DrawingLibDetailsState?.drawingLibDetails[0]?.sheetsReviewed?.pdfRotation : 0
documentViewer.setRotation(rotation)
})
documentViewer.on('pageNumberUpdated', () => {
DrawingLibDetailsDispatch(setDrawingPageNumber(0));
})
}
}, [DrawingLibDetailsState?.parsedFileUrl?.url, newInstance]);
useEffect(() => {
if(DrawingLibDetailsState?.drawingPageNum && newInstance ){
const { documentViewer, PDFNet } = newInstance.Core;
PDFNet.initialize()
documentViewer.addEventListener('documentLoaded',async () => {
await PDFNet.initialize()
const pdfDoc = documentViewer.getDocument();
const doc = await pdfDoc.getPDFDoc();
newInstance.UI.pageManipulationOverlay.add([
{
type: 'customPageOperation',
header: 'Custom options',
dataElement: 'customPageOperations',
operations: [
{
title: 'Alert me',
img: '/path-to-image',
onClick: (selectedPageNumbers:any) => {
alert(`Selected thumbnail pages: ${selectedPageNumbers}`);
},
dataElement: 'customPageOperationButton',
},
],
},
{ type: 'divider' },
]);
documentViewer.setCurrentPage(DrawingLibDetailsState?.drawingPageNum, true);
});
documentViewer.setCurrentPage(DrawingLibDetailsState?.drawingPageNum, true);
}
}, [DrawingLibDetailsState?.drawingPageNum]);
useEffect(() => {
if(props?.drawingSheetsDetails?.fileSize){
fetchSheetUrl(props?.drawingSheetsDetails)
}
}, [props?.drawingSheetsDetails]);
const fetchSheetUrl = (file: any) => {
const payload = [{
fileName: file.fileName,
key: file.sourceKey,
expiresIn: 100000000,
// processed: true
}];
getSheetUrl(payload);
}
const getSheetUrl = async (payload: any) => {
try {
dispatch(setIsLoading(true));
const fileUploadResponse = await postApi('V1/S3/downloadLink', payload);
if(fileUploadResponse.success){
const fileData = {
s3Key: payload[0].key,
url: fileUploadResponse.success[0].url
}
DrawingLibDetailsDispatch(setParsedFileUrl(fileData));
}
dispatch(setIsLoading(false));
} catch (error) {
Notification.sendNotification(error, AlertTypes.warn);
dispatch(setIsLoading(false));
}
}
const updateRotation = (rotation: number) => {
props.updateRotation(rotation)
}
return (
<>
<div className="webviewer" ref={viewer}></div>
</>
)
}
In WebViewer 8.0 you would need to enable the left panel by default when the document is loaded, and then use event delegation on left panel to watch for button clicks on the single page rotation buttons.
const { documentViewer } = instance.Core
documentViewer.addEventListener('documentLoaded',()=>{
let panelElement = instance.docViewer.getScrollViewElement().closest('#app').querySelector('[data-element="thumbnailsPanel"]');
if (!parentElement) {
instance.UI.toggleElementVisibility('leftPanel');
panelElement = instance.docViewer.getScrollViewElement().closest('#app').querySelector('[data-element="thumbnailsPanel"]');
}
panelElement.addEventListener('click', (e) => {
if (e.target.dataset?.element === 'thumbRotateClockwise' || e.target.dataset?.element === 'thumbRotateCounterClockwise') {
// The single page rotations are performed asychronously and there are no events firings in 8.0, so we have to manually add a delay before the page finishes rotating itself.
setTimeout(() => {
const pageNumber = parseInt(e.target.parentElement.previousSibling.textContent);
const rotation = instance.docViewer.getDocument().getPageRotation(pageNumber);
console.log('page ', pageNumber, ' self rotation is ', rotation);
}, 500);
}
});
})
If you have the option to upgrade to the latest WebViewer, you can listen to the ‘pagesUpdated’ event on documentViewer and the code becomes shorter & cleaner:
const { documentViewer } = instance.Core
documentViewer.addEventListener('pagesUpdated',(changes)=>{
changes.contentChanged.forEach(pageNumber=>{
const rotation = documentViewer.getDocument().getPageRotation(pageNumber)
console.log('page ', pageNumber, ' self rotation is ', rotation);
})
})
For both situations, when you load the document back, you can use documentViewer.getDocument().rotatePages to rotate to your saved rotations.
assuming we have the saved page rotations data structured like this
const rotationData = [
{pageNumber: 1, rotation: 180},
{pageNumber: 3, rotation: 90},
{pageNumber: 4, rotation: 270},
]
We can use the following code to rotate our individual pages back:
const { documentViewer } = instance.Core
documentViewer.addEventListener('documentLoaded',()=>{
rotationData.forEach(page=>{
const originalRotation = documentViewer.getDocument().getPageRotation(page.pageNumber)
if (originalRotation !== page.rotation) {
documentViewer.getDocument().rotatePages([page.pageNumber], (page.rotation-originalRotation)/90);
}
})
})
I am trying to achieve cursor pagination on my data table material-ui-datatables.
I am using react js for the front end, express.js backend, and I am using mongo_DB for storage. I want to pass the page number, page limit previous and next as request body from my data table to API and I am using mangoose pagination plugin.
import React, { useState, useEffect } from "react";
import MUIDataTable from "mui-datatables";
import axios from "axios";
import PropagateLoader from "react-spinners/PropagateLoader";
// employee_info
function employee_info() {
let [loading, setLoading] = useState(true);
const [Response, setResponse] = useState([]);
const get_employee_details = () => {
axios
.get(configData.SERVER_URL + "/api/get_employee_info")
.then((res) => {
setResponse(res.data);
setLoading(false);
});
};
useEffect(() => {
const interval = setInterval(() => get_employee_details(), 10000);
return () => {
clearInterval(interval);
};
}, []);
if (loading === true) {
return (
<div style={style}>
<PropagateLoader loading={loading} color={"#36D7B7"} size={30} />
</div>
);
} else {
return EmployeeInfoTable(setResponse);
}
}
//DataTable
function EmployeeInfoTable(value) {
if (
typeof value == "undefined" ||
value == null ||
value.length == null ||
value.length < 0
) {
return <div></div>;
}
const columns = [
{ label: "Employee_ID", name: "employee_id" },
{ label: "Name", name: "name" },
{ label: "Department", name: "department" },
{ label: "Manger", name: "manager" },
];
const data = value.map((item) => {
return [
item.employee_id,
item.name,
item.department,
item.manager,
];
});
const options = {
caseSensitive: true,
responsive: "standard",
selectableRows: "none",
filter: false,
download: false,
print: false,
viewColumns: false,
};
return (
<MUIDataTable
title={"Employee_Details"}
data={data}
columns={columns}
options={options}
/>
);
}
Service API
const MongoPaging = require('mongo-cursor-pagination');
const express = require("express");
const router = express.Router();
router.get('/get_employee_info', async (req, res, next) => {
try {
const result = await MongoPaging.find(db.collection('employee'), {
query: {
employee: req.employee_id
},
paginatedField: 'created',
fields: {
manger: req.manger,
},
limit: req.query.limit,
next: req.query.next,
previous: req.query.previous,
}
res.json(result);
} catch (err) {
next(err);
}
})
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 having an issue with connecting my websocket on port 7777 to my aws deployment. I am new to sockets and deployment. I have my main port 8081 hooked up, but having issues with the websocket. I've been at this for a day and would like some pointers! Thanks!
Currently, receiving this error:
React code
import React from 'react';
import openSocket from 'socket.io-client';
let socket = openSocket('http://my-api.us-east-2.elasticbeanstalk.com:7777', { transports: ['websocket'] });
export class HomePage extends React.Component {
state = {
channels: null,
channelSelected: false,
socket: null,
typers: {},
channel: 1,
messages: [],
msg: ''
}
socket;
componentDidMount() {
}
componentDidUpdate() {
if (this.props.username && !this.state.channelSelected) {
this.configureSocket();
this.setState({ channel: 1, channelSelected: true });
this.socket.emit('joinChannel', { channel: 1, username: this.props.username });
}
}
configureSocket = () => {
socket.on('connection', () => {
if (this.state.channel) {
this.handleChannelSelect(this.state.channel.id);
}
});
socket.on('incomingChat', username => {
let typers = this.state.typers;
if (!typers[username]) {
typers[username] = 1;
this.setState({ typers })
}
});
socket.on('clearingChat', username => {
let typers = this.state.typers;
delete typers[username]
this.setState({ typers });
});
socket.on('incomingMessage', details => {
let messages = this.state.messages;
let typers = this.state.typers;
delete typers[details.username]
messages.push(details);
this.setState({ messages, typers });
})
socket.on('channel', channel => {
let channels = this.state.channels;
channels.forEach(c => {
if (c.id === channel.id) {
c.participants = channel.participants;
}
});
this.setState({ channels });
});
socket.on('message', message => {
let channels = this.state.channels
channels.forEach(c => {
if (c.id === message.channel_id) {
if (!c.messages) {
c.messages = [message];
} else {
c.messages.push(message);
}
}
});
this.setState({ channels });
});
this.socket = socket;
}
handleChannelSelect = e => {
e.preventDefault();
this.setState({ channel: 1 });
this.socket.emit('leaveChannel', this.props.username);
}
handleSendMessage = e => {
e.preventDefault();
this.socket.emit('send-message', { msg: this.state.msg, username: this.props.username, channel: this.state.channel });
this.setState({ msg: '' });
}
handleChange = e => {
const { value } = e.target;
this.setState({ msg: value });
if (!value) this.socket.emit('addingMessage', { username: this.props.username, msg: 'cleared' });
if(value) this.socket.emit('addingMessage', { username: this.props.username, msg: value });
}
render() {
return (
<div className='chat-app'>
<form onSubmit={this.handleSendMessage}>
<input type="text" onChange={this.handleChange} value={this.state.msg} />
</form>
<button onClick={this.handleChannelSelect}></button>
{ this.state.messages.length > 0 && this.state.messages.map(({ username, msg }) => <p key={Math.random()}>{`${username}: ${msg}`}</p>) }
{Object.keys(this.state.typers).length > 0 && Object.keys(this.state.typers).map(el => el !== this.props.username && <p>{`${el} typing....`}</p>)}
</div>
);
}
}
server code
const app = require("./app");
const socketio = require('socket.io');
const express = require('express');
const http = require('http');
const db = require("./db");
const AWS = require("aws-sdk");
const CryptoJS = require("crypto-js");
const em = express();
const server = http.createServer(em);
const chatPort = process.env.LIVE_CHAT_PORT || 7777;
const io = socketio(server);
server.listen(chatPort, () => {
console.log(`Live Chat sock running on port ${chatPort}`)
});
app.listen(process.env.PORT || 8081, () => {
console.log("Listening on PORT 8081");
});
io.on('connection', socket => {
let user;
socket.on('joinChannel', async ({ username, channel }) => {
user = userJoin(socket.id, username, channel);
socket.on('addingMessage', details => {
const { username, msg } = details;
if (msg === 'cleared') {
io.to(user.room).emit('clearingChat', username);
} else {
io.to(user.room).emit('incomingChat', username);
}
})
socket.join(user.room);
});
socket.on('send-message', async details => {
const { msg, username, channel } = details;
let em = await db.query(`
INSERT INTO messages(conversation_id, user_id, shared_post, message, posted)
VALUES($1, $2, null, $3, current_timestamp)
RETURNING id;
`, [channel, username, msg])
io.to(user.room).emit('incomingMessage', details)
})
socket.on('leaveChannel', username => {
const user = userLeave(username);
socket.disconnect();
});
});