소스 검색

Added redis, websocket containers

Alexander Musikhin 11 달 전
부모
커밋
ab17f703fa
5개의 변경된 파일131개의 추가작업 그리고 37개의 파일을 삭제
  1. 5 5
      Dockerfile
  2. 30 32
      docker-compose.yml
  3. 6 0
      docker/websocket/Dockerfile
  4. 14 0
      docker/websocket/package.json
  5. 76 0
      docker/websocket/server.js

+ 5 - 5
Dockerfile

@@ -37,11 +37,11 @@ RUN docker-php-ext-install zip \
 
 RUN yes | pecl install ${XDEBUG_VERSION}
 
-#RUN curl --insecure 'https://pecl.php.net/get/redis-5.3.7.tgz' -o redis-5.3.7.tgz \
-#    && pecl install --offline redis-5.3.7.tgz \
-#    && rm -rf redis-5.3.7.tgz \
-#    && rm -rf /tmp/pear \
-#    && docker-php-ext-enable redis
+RUN curl --insecure 'https://pecl.php.net/get/redis-5.3.7.tgz' -o redis-5.3.7.tgz \
+    && pecl install --offline redis-5.3.7.tgz \
+    && rm -rf redis-5.3.7.tgz \
+    && rm -rf /tmp/pear \
+    && docker-php-ext-enable redis
 
 # install composer
 RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

+ 30 - 32
docker-compose.yml

@@ -40,12 +40,12 @@ services:
     depends_on:
       db:
         condition: service_healthy
-#      redis:
-#        condition: service_healthy
+      redis:
+        condition: service_healthy
       webserver:
         condition: service_started
-#      websocket:
-#        condition: service_started
+      websocket:
+        condition: service_started
 #      minio:
 #        condition: service_healthy
 
@@ -92,35 +92,33 @@ services:
     networks:
       - cpa-network
 
-#  websocket:
-#    build:
-#      context: docker/websocket
-#      dockerfile: Dockerfile
-#    restart: unless-stopped
-#    environment:
-#      - JWT_SECRET=${JWT_SECRET}
-#      - REDIS_PASSWORD=${REDIS_PASSWORD}
-#    tty: true
-#    command: '/bin/sh -c ''node server'''
-#    ports:
-#      - ${WS_PORT:-3000}:3000
-#    networks:
-#      - cpa-network
-#    depends_on:
-#      redis:
-#        condition: service_healthy
+  websocket:
+    build:
+      context: docker/websocket
+      dockerfile: Dockerfile
+    restart: unless-stopped
+    environment:
+      - JWT_SECRET=${JWT_SECRET}
+      - REDIS_PASSWORD=${REDIS_PASSWORD}
+    tty: true
+    command: '/bin/sh -c ''node server'''
+    ports:
+      - ${WS_PORT:-3000}:3000
+    networks:
+      - cpa-network
+    depends_on:
+      redis:
+        condition: service_healthy
 
-#  redis:
-#    image: "redis:alpine"
-#    command: redis-server --requirepass ${REDIS_PASSWORD}
-#    environment:
-#      - REDIS_REPLICATION_MODE=master
-#    networks:
-#      - cpa-network
-#    volumes:
-#      - redis:/data
-#    healthcheck:
-#      test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
+  redis:
+    image: "redis:alpine"
+    command: redis-server --requirepass ${REDIS_PASSWORD}
+    environment:
+      - REDIS_REPLICATION_MODE=master
+    networks:
+      - cpa-network
+    healthcheck:
+      test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
 
 #  minio:
 #    image: minio/minio

+ 6 - 0
docker/websocket/Dockerfile

@@ -0,0 +1,6 @@
+FROM node
+RUN mkdir app
+COPY ./ /app
+WORKDIR /app
+EXPOSE 3000
+RUN npm i

+ 14 - 0
docker/websocket/package.json

@@ -0,0 +1,14 @@
+{
+    "name": "socket-chat-example",
+    "version": "0.0.1",
+    "description": "The socket.io server",
+    "type": "module",
+    "license": "MIT",
+    "dependencies": {
+        "dotenv": "^16.0.1",
+        "fs": "^0.0.1-security",
+        "ioredis": "^5.0.6",
+        "jsonwebtoken": "9.0.2",
+        "socket.io": "4.7.2"
+    }
+}

+ 76 - 0
docker/websocket/server.js

@@ -0,0 +1,76 @@
+import { Server } from "socket.io";
+import { Redis } from "ioredis";
+import jwt from "jsonwebtoken";
+
+const jwtSecret = process.env.JWT_SECRET;
+const port = process.env.PORT || 3000;
+const io = new Server(port, {
+    cors: {
+        origin: "*",
+        credentials: true,
+    },
+});
+const redis = new Redis({
+    port: 6379,
+    host: "redis",
+    username: "default",
+    password: process.env.REDIS_PASSWORD,
+    db: 0,
+});
+
+io.engine.use((req, res, next) => {
+    const isHandshake = req._query.sid === undefined;
+
+    if (!isHandshake) {
+        return next();
+    }
+
+    const header = req.headers["authorization"];
+
+    if (!header) {
+        return next(new Error("no token"));
+    }
+
+    if (!header.startsWith("Bearer ")) {
+        return next(new Error("invalid token"));
+    }
+
+    const token = header.substring(7);
+
+    jwt.verify(token, jwtSecret, (err, decoded) => {
+        if (err) {
+            return next(new Error("invalid token"));
+        }
+        req.decodedToken = decoded;
+        next();
+    });
+
+});
+
+io.on("connection", (socket) => {
+    console.log(`connected with transport ${socket.conn.transport.name} and socket ${socket.id}`);
+
+    socket.conn.on("upgrade", (transport) => {
+        console.log(`transport upgraded to ${transport.name}`);
+    });
+
+    socket.on("disconnect", (reason) => {
+        console.log(`disconnected ${socket.id} due to ${reason}`);
+    });
+
+    if(socket.request.decodedToken){
+        let user_id = parseInt(socket.request.decodedToken.sub)
+        socket.join(user_id);
+    }
+});
+
+redis.subscribe("actions", (err, count) => {
+    if (err) console.error(err.message);
+    console.log(`Subscribed to ${count} channels.`);
+});
+
+redis.on("message", function (channel, data) {
+    data = JSON.parse(data).data;
+    io.to(data.user_id).emit(data.action, data);
+    console.log(`send new message to user ${data.user_id} in the channel '${channel}'.`);
+});