ABOUT ME

Today
Yesterday
Total
  • socket.io를 이용한 채팅 서비스 구현
    Javascript/Node.js 2020. 1. 29. 14:19

    schema

    본 프로젝트에서는 nosql인 mongoDB를 사용했다. 스키마 설계는 다음과 같이 하였다.

    Room은 채팅방에 관한 정보가 들어있으며, 비밀번호가 있으면 비밀방이다. Chat에 존재하는 room을 이용해 Room schema를 참조할 수 있다.

     

    packages

    "dependencies": {
    "axios": "^0.18.0",
    "color-hash": "^1.0.3",
    "connect-flash": "^0.1.1",
    "cookie-parser": "^1.4.4",
    "dotenv": "^7.0.0",
    "express": "^4.16.4",
    "express-session": "^1.15.6",
    "mongoose": "^5.4.20",
    "morgan": "^1.9.1",
    "multer": "^1.4.1",
    "pug": "^2.0.3",
    "socket.io": "^2.2.0",
    "ws": "^5.2.2"
    },
    view raw package.json hosted with ❤ by GitHub

    소스 코드(핵심)

    app.js

    const express = require('express');
    const path = require('path');
    const morgan = require('morgan');
    const cookieParser = require('cookie-parser');
    const session = require('express-session');
    const flash = require('connect-flash');
    // 랜덤 색상을 구현해주는 모듈
    const ColorHash = require('color-hash');
    require('dotenv').config();
    const webSocket = require('./socket');
    const indexRouter = require('./routes');
    const connect = require('./schemas');
    const app = express();
    // 몽고디비와 연결
    connect();
    // 세션을 저장
    const sessionMiddleware = session({
    resave: false,
    saveUninitialized: false,
    secret: process.env.COOKIE_SECRET,
    cookie: {
    httpOnly: true,
    secure: false,
    },
    });
    /* ... */
    // 'gif/'는 uploads 폴더에서부터 시작
    app.use('/gif', express.static(path.join(__dirname, 'uploads')));
    /* ... */
    // cookie에서 .env에 있는 비밀번호 사용
    app.use(cookieParser(process.env.COOKIE_SECRET));
    app.use(sessionMiddleware);
    app.use(flash());
    // 만약 session에 color가 존재하지 않는다면 새로 color를 만들어줌
    app.use((req, res, next) => {
    if (!req.session.color) {
    const colorHash = new ColorHash();
    req.session.color = colorHash.hex(req.sessionID);
    }
    next();
    });
    /* ... */
    view raw app.js hosted with ❤ by GitHub

     

    socket.js

    const SocketIO = require('socket.io');
    const axios = require('axios');
    module.exports = (server, app, sessionMiddleware) => {
    const io = SocketIO(server, { path: '/socket.io' });
    // 라우터에서 io 객체를 쓸 수 있게 해줌. req.app.get('io')로 접근 가능하다.
    app.set('io', io);
    // of 메소드는 네임스페이스를 부여
    const room = io.of('/room');
    const chat = io.of('/chat');
    io.use((socket, next) => {
    sessionMiddleware(socket.request, socket.request.res, next);
    });
    room.on('connection', (socket) => {
    console.log('room 네임스페이스에 접속');
    socket.on('disconnect', () => {
    console.log('room 네임스페이스 접속 해제');
    });
    });
    chat.on('connection', (socket) => {
    console.log('chat 네임스페이스에 접속');
    // 소켓에 존재하는 request 객체 뽑기
    const req = socket.request;
    // headers에 있는 referer 뽑기
    // socket.request.headers.referer에서 현제 웹 페이지 URL을 가져올 수 있고,
    // URL에서 room id 추출할 수 있다.
    const { headers: { referer } } = req;
    // referer에서 '/'으로 split 하고 맨 끝에 있는게 roomId인데 /\?.+/을 '' 로 교체
    // 암튼 이렇게 하면 referer에서 roomId 뽑을 수 있음
    const roomId = referer
    .split('/')[referer.split('/').length - 1]
    .replace(/\?.+/, '');
    // 이 roomId로 join
    socket.join(roomId);
    // 이 방에 시스템 메세지로 아래 메세지 전송
    socket.to(roomId).emit('join', {
    user: 'system',
    chat: `${req.session.color}님이 입장하셨습니다.`,
    });
    socket.on('disconnect', () => {
    console.log('chat 네임스페이스 접속 해제');
    // 방 나가기
    socket.leave(roomId);
    const currentRoom = socket.adapter.rooms[roomId];
    const userCount = currentRoom ? currentRoom.length : 0;
    // 이 방에 사람이 없다면 방 제거
    if (userCount === 0) {
    axios.delete(`http://localhost:8005/room/${roomId}`)
    .then(() => {
    console.log('방 제거 요청 성공');
    })
    .catch((error) => {
    console.error(error);
    });
    } else {
    // 아직 사람이 있다면 시스템 메세지 전송
    socket.to(roomId).emit('exit', {
    user: 'system',
    chat: `${req.session.color}님이 퇴장하셨습니다.`,
    });
    }
    });
    });
    };
    view raw socket.js hosted with ❤ by GitHub

     

    실행화면

     

    출처

    https://github.com/zeroCho/nodejs-book

     

    ZeroCho/nodejs-book

    Contribute to ZeroCho/nodejs-book development by creating an account on GitHub.

    github.com

     

    'Javascript > Node.js' 카테고리의 다른 글

    socket.io  (0) 2020.01.28
    웹 소켓  (0) 2020.01.28
    Mocha  (0) 2020.01.28
    middleware  (0) 2020.01.22
    express  (0) 2020.01.22
Designed by Tistory.