Browse Source

first commit

kevin 2 năm trước cách đây
commit
f36cda4893
12 tập tin đã thay đổi với 215 bổ sung0 xóa
  1. 3 0
      .dockerignore
  2. 2 0
      .gitignore
  3. 16 0
      Dockerfile
  4. 0 0
      README.md
  5. 11 0
      docker-compose.yaml
  6. 22 0
      package.json
  7. 61 0
      public/script.js
  8. 14 0
      run.sh
  9. 49 0
      server.js
  10. 3 0
      start_docker.sh
  11. 3 0
      stop_docker.sh
  12. 31 0
      views/room.ejs

+ 3 - 0
.dockerignore

@@ -0,0 +1,3 @@
+Dockerfile
+package-lock.json
+node_modules

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+node_modules
+package-lock.json

+ 16 - 0
Dockerfile

@@ -0,0 +1,16 @@
+FROM node:20-alpine
+
+WORKDIR /app
+
+# ENV NODE_ENV=development
+ENV NODE_ENV=production NPM_CONFIG_LOGLEVEL=info
+
+ENV PATH="${PATH}:/app/node_modules/.bin"
+
+COPY . .
+
+RUN npm install
+
+EXPOSE 4230 4231
+
+CMD ["/app/run.sh"]

+ 0 - 0
README.md


+ 11 - 0
docker-compose.yaml

@@ -0,0 +1,11 @@
+version: '3'
+services:
+  web:
+    build: .
+    restart: always
+    ports:
+      - "4230:4230"
+      - "4231:4231"
+    environment:
+      - NODE_ENV=production
+      - NPM_CONFIG_LOGLEVEL=info

+ 22 - 0
package.json

@@ -0,0 +1,22 @@
+{
+  "name": "signal-webrtc",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "devStart": "nodemon server.js"
+  },
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "ejs": "^3.1.9",
+    "express": "^4.18.2",
+    "peer": "^1.0.0",
+    "socket.io": "^4.7.2",
+    "uuid": "^9.0.0"
+  },
+  "devDependencies": {
+    "nodemon": "^3.0.1"
+  }
+}

+ 61 - 0
public/script.js

@@ -0,0 +1,61 @@
+const socket = io('/')
+const videoGrid = document.getElementById('video-grid')
+let myPeer = null
+const myVideo = document.createElement('video')
+myVideo.muted = true
+const peers = {}
+navigator.mediaDevices.getUserMedia({
+  video: true,
+  audio: true
+}).then(stream => {
+    myPeer = new Peer(undefined, {
+        host: '/',
+        port: '4231'
+      })
+  addVideoStream(myVideo, stream)
+
+  myPeer.on('call', call => {
+    call.answer(stream)
+  })
+
+  myPeer.on('open', id => {
+    socket.emit('join-room', ROOM_ID, id)
+  })
+
+  socket.on('connected-clients', connectedClients => {
+    for (const userId in connectedClients) {
+        connectToNewUser(connectedClients[userId], stream)
+    }
+  })
+
+  socket.on('user-connected', userId => {
+    connectToNewUser(userId, stream)
+  })
+}).catch(error=>{
+    console.log("Error: ",error)
+})
+
+socket.on('user-disconnected', userId => {
+  if (peers[userId]) peers[userId].close()
+})
+
+function connectToNewUser(userId, stream) {
+  const call = myPeer.call(userId, stream)
+  const video = document.createElement('video')
+  call.on('stream', userVideoStream => {
+    addVideoStream(video, userVideoStream)
+  })
+  call.on('close', () => {
+    video.remove()
+  })
+
+  peers[userId] = call
+}
+
+function addVideoStream(video, stream) {
+  video.srcObject = stream
+  video.addEventListener('loadedmetadata', () => {
+    video.play()
+  })
+  videoGrid.append(video)
+}

+ 14 - 0
run.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+_term() {
+  kill $PEER_PID $SERVER_PID
+  exit 0
+}
+
+trap _term 2 15
+
+peerjs --port 4231 &
+PEER_PID=$!
+node server.js &
+SERVER_PID=$!
+wait -n "$PEER_PID" "$SERVER_PID"

+ 49 - 0
server.js

@@ -0,0 +1,49 @@
+const express = require('express')
+const app = express()
+const server = require('http').Server(app)
+const io = require('socket.io')(server)
+const { v4: uuidV4 } = require('uuid')
+
+const connectedClients = {} // {"roomId1": ["userId1", "userId2"], "roomId2" : ["userId3"]}
+
+app.set('view engine', 'ejs')
+app.use(express.static('public'))
+
+app.get('/', (req, res) => {
+  res.redirect(`/${uuidV4()}`)
+})
+
+app.get('/:room', (req, res) => {
+  res.render('room', { roomId: req.params.room })
+})
+
+io.on('connection', socket => {
+
+  socket.on('join-room', (roomId, userId) => {
+    if(!(roomId in connectedClients)){
+      connectedClients[roomId] = []
+    }
+    socket.emit('connected-clients', connectedClients[roomId]);
+    connectedClients[roomId].push(userId)
+    socket.join(roomId)
+    socket.to(roomId).emit('user-connected', userId)
+
+    socket.on('disconnect', () => {
+      socket.to(roomId).emit('user-disconnected', userId)
+      const index = connectedClients[roomId].indexOf(socket.id)
+      if (index !== -1) {
+        connectedClients[roomId].splice(index, 1)
+        if(connectedClients[roomId].length == 0){
+          delete connectedClients[roomId]
+        }
+      }
+    })
+  })
+})
+
+server.listen(4230)
+
+process.on('SIGTERM', () => {
+  console.info("Interrupted");
+  process.exit(0);
+})

+ 3 - 0
start_docker.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+docker-compose build --no-cache && docker-compose up "$@"

+ 3 - 0
stop_docker.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+docker-compose down

+ 31 - 0
views/room.ejs

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="ie=edge">
+  <script>
+    const ROOM_ID = "<%= roomId %>"
+  </script>
+  <script defer src="https://unpkg.com/peerjs@1.4.7/dist/peerjs.min.js"></script>
+  <script src="/socket.io/socket.io.js" defer></script>
+  <script src="script.js" defer></script>
+  <title>Document</title>
+  <style>
+    #video-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fill, 300px);
+      grid-auto-rows: 300px;
+    }
+    
+    video {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+    }
+  </style>
+</head>
+<body>
+  <div id="video-grid"></div>
+</body>
+</html>