Skip to content

WebNinjaDeveloper.com

Programming Tutorials




Menu
  • Home
  • Youtube Channel
  • PDF Invoice Generator
Menu

Build a React.js P2P File Sharing Project in Node.js & Express Using Socket.io Rooms in Browser

Posted on April 13, 2023

 

 

Welcome folks today in this blog post we will be building a simple p2p file sharing project in react.js and node.js and express using socket.io and simple-peer in browser using javascript. All the full source code of the application is shown below.

 

 

LIVE DEMO

 

 

https://p2pfiletransfer.herokuapp.com/

 

 

Get Started

 

 

In order to get started you need to make a new p2p folder and inside it we will be making the backend and the frontend of the application

 

 

mkdir p2p

 

 

cd p2p

 

 

And now we need to initialize a node.js project using the below command

 

 

npm init -y

 

 

Now we need to install the express and the socket.io libraries using the below command

 

 

npm i express

 

 

npm i socket.io

 

 

And now you need to make the index.js file and copy paste the following code

 

 

index.js

 

 

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
const express = require("express");
const http = require("http");
const app = express();
const path = require('path')
 
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server);
 
const users = {};
 
const socketToRoom = {};
 
io.on("connection", (socket) => {
  socket.on("join room", (roomID) => {
    if (users[roomID]) {
      const length = users[roomID].length;
      if (length === 2) {
        socket.emit("room full");
        return;
      }
      users[roomID].push(socket.id);
    } else {
      users[roomID] = [socket.id];
      console.log(users);
      console.log(users[roomID]);
    }
    socketToRoom[socket.id] = roomID;
    console.log("dsd" + socketToRoom);
    console.log("sfsfsdf" + socketToRoom[socket.id]);
    const usersInThisRoom = users[roomID].filter((id) => id !== socket.id);
 
    socket.emit("all users", usersInThisRoom);
  });
 
  socket.on("sending signal", (payload) => {
    io.to(payload.userToSignal).emit("user joined", {
      signal: payload.signal,
      callerID: payload.callerID,
    });
  });
 
  socket.on("returning signal", (payload) => {
    io.to(payload.callerID).emit("receiving returned signal", {
      signal: payload.signal,
      id: socket.id,
    });
  });
 
  socket.on("disconnect", () => {
    const roomID = socketToRoom[socket.id];
    let room = users[roomID];
    if (room) {
      room = room.filter((id) => id !== socket.id);
      users[roomID] = room;
      socket.broadcast.emit("user left", socket.id);
    }
  });
});
 
server.listen(process.env.PORT || 8000, () =>
  console.log("server is running on port 8000")
);

 

 

As you can see we are starting a basic express app and then we are passing it to the socket.io server and then we have the various events where we listen for connection of the socket and the disconnection of the socket.

 

 

Now we need to make the client folder and inside it we will be making the react.js app as shown below

 

 

cd client

 

 

npm create vite@ p2pclient

 

 

cd p2pclient

 

 

npm i

 

 

Now we need to install the below dependencies as shown below

 

 

npm i react-bootstrap bootstrap

 

 

npm i streamsaver

 

 

npm i simple-peer

 

 

npm i uuid

 

 

npm i socket.io-client

 

 

npm i react-router-dom

 

 

npm i buffer

 

 

And now you will see the below directory structure of the react.js app as shown below

 

 

 

 

And now we need to go to App.js file and copy paste the following code

 

 

App.js

 

 

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from 'react';
import { BrowserRouter, Route, Switch } from "react-router-dom";
import CreateRoom from "./routes/CreateRoom";
import Room from "./routes/Room";
 
function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/p2p" exact component={CreateRoom} />
        <Route path="/p2p/room/:roomID" component={Room} />
      </Switch>
    </BrowserRouter>
  );
}
 
export default App;

 

 

As you can see in the above code we are writing the various routes for our application. And for this we are using the browserRouter and inside it we are defining the routes and inside it we are loading the various components.

 

 

And now we need to define the routes folder and inside it we need to define the below files

 

 

routes/CreateRoom.js

 

 

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react";
import { v1 as uuid } from "uuid";
import 'bootstrap/dist/css/bootstrap.min.css';
import { Button,Container } from 'react-bootstrap';
 
const CreateRoom = (props) => {
    function create() {
        const id = uuid();
        props.history.push(`/p2p/room/${id}`);
    }
 
    return (
        <Container className="text-center">
        <br/><br/>
        <h1>P2P File Transfer</h1>
        <br/><br/>
        <Button className="btn btn-danger" onClick={create}>Create room</Button>
        </Container>
    );
};
 
export default CreateRoom;

 

 

As you can see this will be the page which will be shown to the user once user goes to the / homepage and we have the simple button here to create the room here as shown below

 

 

 

 

And now we need to define the Room.js file and copy paste the following code

 

 

routes/Room.js

 

 

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import React, { useEffect, useRef, useState } from "react";
import io from "socket.io-client";
import Peer from "simple-peer";
import streamSaver from "streamsaver";
import "bootstrap/dist/css/bootstrap.min.css";
import { Button, Container, Spinner, Form } from "react-bootstrap";
import { useHistory } from "react-router-dom";
 
const worker = new Worker("../worker.js");
 
const Room = (props) => {
  const [connectionEstablished, setConnection] = useState(false);
  const [file, setFile] = useState();
  const [gotFile, setGotFile] = useState(false);
  const history = useHistory();
 
  const socketRef = useRef();
  const peerRef = useRef();
  const fileNameRef = useRef("");
 
  const roomID = props.match.params.roomID;
 
  useEffect(() => {
    socketRef.current = io.connect("/");
    socketRef.current.emit("join room", roomID);
    socketRef.current.on("all users", (users) => {
      peerRef.current = createPeer(users[0], socketRef.current.id);
    });
 
    socketRef.current.on("user joined", (payload) => {
      peerRef.current = addPeer(payload.signal, payload.callerID);
    });
 
    socketRef.current.on("receiving returned signal", (payload) => {
      peerRef.current.signal(payload.signal);
      setConnection(true);
    });
 
    socketRef.current.on("room full", () => {
      alert("room is full");
      history.goBack();
    });
  }, []);
 
  function createPeer(userToSignal, callerID) {
    const peer = new Peer({
      initiator: true,
      trickle: false,
    });
 
    peer.on("signal", (signal) => {
      socketRef.current.emit("sending signal", {
        userToSignal,
        callerID,
        signal,
      });
    });
 
    peer.on("data", handleReceivingData);
 
    return peer;
  }
 
  function addPeer(incomingSignal, callerID) {
    const peer = new Peer({
      initiator: false,
      trickle: false,
    });
 
    peer.on("signal", (signal) => {
      socketRef.current.emit("returning signal", { signal, callerID });
    });
 
    peer.on("data", handleReceivingData);
 
    peer.signal(incomingSignal);
    setConnection(true);
    return peer;
  }
 
  function handleReceivingData(data) {
    if (data.toString().includes("done")) {
      setGotFile(true);
      const parsed = JSON.parse(data);
      fileNameRef.current = parsed.fileName;
    } else {
      worker.postMessage(data);
    }
  }
 
  function download() {
    setGotFile(false);
    worker.postMessage("download");
    worker.addEventListener("message", (event) => {
      const stream = event.data.stream();
      const fileStream = streamSaver.createWriteStream(fileNameRef.current);
      stream.pipeTo(fileStream);
    });
  }
 
  function selectFile(e) {
    setFile(e.target.files[0]);
  }
 
  function sendFile() {
    const peer = peerRef.current;
    const stream = file.stream();
    console.log(stream);
    const reader = stream.getReader();
    console.log(reader);
 
    reader.read().then((obj) => {
      handlereading(obj.done, obj.value);
    });
 
    function handlereading(done, value) {
      if (done) {
        peer.write(JSON.stringify({ done: true, fileName: file.name }));
        return;
      }
 
      peer.write(value);
      reader.read().then((obj) => {
        handlereading(obj.done, obj.value);
      });
    }
  }
 
  let copy = () => {
    let text = document.getElementById("text");
    text.select();
    document.execCommand("copy");
  };
 
  let body;
  if (connectionEstablished) {
    body = (
      <Container className="text-center">
        <br />
        <br />
        <h1>Connected With Peer (You can Share or Transfer Files)</h1>
        <br/><br/>
        <Form>
          <Form.Label>Select the File:</Form.Label>
          <Form.Control
            size="lg"
            onChange={selectFile}
            type="file"
          ></Form.Control>
        </Form>
        <br/>
        <Button onClick={sendFile}>Send file</Button>
      </Container>
    );
  } else {
    body = (
      <Container className="text-center">
        <br />
        <br />
        <br />
        <h1>Waiting for the Peer to Join</h1>
        <br />
        <br />
        <Spinner animation="grow" variant="primary" />
        <Spinner animation="grow" variant="success" />
        <Spinner animation="grow" variant="danger" />
        <br />
        <br />
        <Form>
          <Form.Group>
            <Form.Label>Your Room URL: (Share with Anyone in World)</Form.Label>
            <br />
            <br />
            <Form.Control
              size="lg"
              id="text"
              type="text"
              value={window.location.href}
              readOnly
            />
          </Form.Group>
          <br />
          <Button onClick={copy} variant="primary">
            Copy to Clipboard
          </Button>
        </Form>
      </Container>
    );
  }
 
  let downloadPrompt;
  if (gotFile) {
    downloadPrompt = (
      <Container className="text-center">
        <br/><br/>
        <h3>
          You have received a file. Would you like to download the file?
        </h3>
        <br/>
        <Button onClick={download}>Yes</Button>
      </Container>
    );
  }
 
  return (
    <Container>
      {body}
      {downloadPrompt}
    </Container>
  );
};
 
export default Room;

 

 

 

 

 

 

As you can see we are connecting the two sockets with each other first of all we need to create the room and share the link with other one and as soon as the other peer joins it will automatically give you the html form where you can transfer the files over the p2p data channel and now we need to define the worker.js file inside the public folder as shown below

 

 

 

 

public/worker.js

 

 

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let array = [];
self.addEventListener("message", event => {
    console.log(event.data)
    if (event.data === "download") {
        console.log(array)
        const blob = new Blob(array);
        console.log(blob)
        self.postMessage(blob);
        array = [];
    } else {
        console.log("else" + event.data)
        array.push(event.data);
    }
})

 

 

As you can see inside this file we are just downloading the file which is transferred over the p2p data channel as an attachment.

 

 

https://github.com/gauti123456/p2pfiletransfer

 

Recent Posts

  • Node.js Express Project to Remove Background of Images Using Rembg & Formidable Library in Browser
  • Node.js Tutorial to Remove Background From Image Using Rembg & Sharp Library in Command Line
  • Python 3 Flask Project to Remove Background of Multiple Images Using Rembg Library in Browser
  • Python 3 Rembg Library Script to Bulk Process Multiple Images and Remove Background in Command Line
  • Python 3 Rembg Library Script to Remove Background From Image in Command Line
  • Angular
  • Bunjs
  • C#
  • Deno
  • django
  • Electronjs
  • java
  • javascript
  • Koajs
  • kotlin
  • Laravel
  • meteorjs
  • Nestjs
  • Nextjs
  • Nodejs
  • PHP
  • Python
  • React
  • ReactNative
  • Svelte
  • Tutorials
  • Vuejs




©2023 WebNinjaDeveloper.com | Design: Newspaperly WordPress Theme