чорнетка сокети

Встановимо на бекенді

npm i socket.io

сокети працюють окремо від експрес. Підрефакторимо індекс фапйл

const socketIO = require("socket.io")

і треба підправити запуск сервера так, зоб підключити сокети до нашого сервера

// ===========SERVER INIT=========== //
const server = app.listen(3000, () => {
  console.log("server is up and runned on port 3000");
});

// ===========SOCKET EXAMPLE =========== //
const io = socketIO(server);

io.on("connection", (socket) => {
  // логування на бекенді
  console.log("Socket is connected..");

  // відправка в консоль на фронтенд із бекенду
  socket.emit("message", { msg: "Hello from socket!" });

  socket.on("custom event", (data) => {
    console.log(data);
  });
});

module.exports = server;

А фронтенд відпрацюємо із статичних файдів

у папці static створимо файл chat.html

і в ньому створимо верстку чату, але зараз головне, зоб фронтенд і бекенд обмінядися подіями і месеждами

<!-- Код верстки -->
 
 <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io.connect('http://localhost:3000');

      socket.on('message', (data) => {
        console.log(data);
       // відправка в консоль на бекенд із фронтенду
        socket.emit('custom event', { msg: 'Hello from client!' });
      });
</script>

а після цього запустити сервер і зайти в браузер http://localhost:3000/chat.html

то в консолі як на сервері так і в браузері побачимо обмін повідомленнями.

ПОРЕФАКТОРИМО БЕКЕНД РОЗШИРИМО ФУНКЦІЇ

НАПИШЕМО ЧАТ

створимо на бекенді і фронтенді кастомний івент "message"

прим connect - це дефолтний івент

бек
io.on("connection", (socket) => {
  socket.on("message", (msg) => {
    console.log(`Message from client: ${msg}`);

    io.emit("message", msg);
  });
});

фронт

чат
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Static page</h1>
    <p>Socket io example</p>
    <div class="container">
      <ul id="messages"></ul>
      <form id="msgForm">
        <div class="input-group">
          <input id="msg" type="text" autocomplete="false" />
          <button type="submit">send</button>
        </div>
      </form>
    </div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io.connect("http://localhost:3000");

      document.getElementById("msgForm").addEventListener("submit", (event) => {
        event.preventDefault();

        const msgField = document.getElementById("msg");

        socket.emit("message", msgField.value);

        msgField.value = "";
      });

      socket.on("message", (msg) => {
        const messages = document.getElementById("messages");

        messages.insertAdjacentHTML("afterbegin", `<li>${msg}</li>`);
      });

      socket.on("connect", () => {
        socket.emit("message", "new user connected..");
      });
    </script>
  </body>
</html>

в цьому прикладі бекенд приймає повідомлення з форми при сабміті і одразу відправляє по події його назад клієнту.

А у фронті він чекає на подію message і як тільки вона відбувається виводить у список отримане повідомлення крім того. дефолтна подія connect при приєднанні нового користувача видасть нове повідомлення у всі х у кого відкритий цей фронт.

примітка: тут можна прописати стилі для фронта для краси

ПОРЕФАКТОРИМО. СТВОРИМО РУМИ. І БУДЕМО КОНЕКТИТИСЬ НЕ ДО ОДНОГО ЗАГАЛЬНОГО ЧАТУ А ДО РІЗНИХ КІМНАТ і вводити імʼя юзера

створимо для фронти у папці статік новий файли javascript.html і python.html для різних кімнат для спілкування.

також у файдах створимо другу форму для логіна. а офновна форма буле неактивна. при вході до долучення до чату спочатку залогінимося а потім тільки буде можливість віжправляти повідомлення

на сервері можна завести кілька сокетів namespace

бекенд

const nodeNameSpace = io.of('/nodeNameSpace');

nodeNameSpace.on('connection', (socket) => {
  socket.on('join', (data) => {
    socket.join(data.room);

    nodeNameSpace
      .in(data.room)
      .emit('message', { msg: `${data.nick ? '' : 'New user '}joined ${data.room} room`, nick: data.nick });
  });

  socket.on('message', (data) => {
    nodeNameSpace.in(data.room).emit('message', { msg: data.msg, nick: data.nick });
  });
});

У цьому коді ми робимо все як і раніше, тільки ще ділимо по "кімнатах"

nodeNameSpace - приходитиме з фронту - кямната до якої ми приєднаємося при ешені on отримуємо data.room і за допомогою метода join приєднуємося до тієї кімнати

після цього тільки у цій кімнаті повертаємо повідомлення за допомогоюб метода emit.

далі у випалку виникнення події message ми отримуємо data і повертаємо в той же рум повідомлення.

тепер пропишемо фронт кімнати javascript.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      html {
        margin: 0;
        padding: 0;
      }
      body {
        background-color: bisque;
        margin: 0;
        padding: 0;
      }
      h1,
      p {
        text-align: center;
      }
      .container {
        width: 100rem;
        margin: 0 auto;
      }
      ul {
        border: 1px solid orangered;
        border-radius: 0.5rem;
        background-color: white;
        height: 60vh;
        list-style: none;
        padding: 1rem;
        overflow-y: auto;
        display: flex;
        flex-direction: column-reverse;
      }
      li {
        font-size: 1.3rem;
        color: lightslategray;
      }
      .input-group {
        display: flex;
        justify-content: space-between;
        height: 3rem;
      }
      .input-group input {
        border: 1px solid lightcyan;
        outline: none;
        width: 100%;
        margin-right: 2rem;
        padding: 0 1rem;
        border-radius: 0.5rem;
        display: block;
      }
      .input-group input::placeholder {
        color: lightslategray;
        font-family: serif;
      }
      .input-group button {
        border: none;
        outline: none;
        background-color: darkred;
        padding: 0 3rem;
        border-radius: 0.5rem;
        color: white;
        text-transform: uppercase;
        font-size: 1rem;
        line-height: 1rem;
      }
      .inactive {
        display: none;
      }
    </style>
  </head>
  <body>
    <h1>Static page</h1>
    <p>Socket io example</p>
    <div class="container">
      <ul id="messages"></ul>
      <form id="msgForm" class="inactive">
        <div class="input-group">
          <input
            id="msg"
            type="text"
            autocomplete="false"
            placeholder="enter message"
          />
          <button type="submit">send</button>
        </div>
      </form>
      <form id="nickForm">
        <div class="input-group">
          <input
            id="nick"
            type="text"
            autocomplete="false"
            placeholder="enter your nickname"
          />
          <button type="submit">join</button>
        </div>
      </form>
    </div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      let nick;
      let socket;
      const room = "javascript";

      const initSocket = (room, nick) => {
        socket = io.connect("/nodeNameSpace");

        socket.on("message", ({ nick, msg }) => {
          const messages = document.getElementById("messages");

          messages.insertAdjacentHTML(
            "afterbegin",
            `<li><span style="color: orangered; font-style: italic">${nick}</span>&nbsp;${msg}</li>`
          );
        });

        socket.on("connect", () => {
          socket.emit("join", { room, nick });
        });
      };

      const nickForm = document.getElementById("nickForm");
      const msgForm = document.getElementById("msgForm");

      nickForm &&
        nickForm.addEventListener("submit", (event) => {
          event.preventDefault();

          const nickField = document.getElementById("nick");

          if (!nickField?.value) return;

          nick = nickField.value;

          initSocket(room, nick);

          msgForm.classList.remove("inactive");
          nickForm.classList.add("inactive");
        });

      msgForm &&
        msgForm.addEventListener("submit", (event) => {
          event.preventDefault();

          const msgField = document.getElementById("msg");

          socket.emit("message", { msg: msgField.value, room, nick });

          msgField.value = "";
        });
    </script>
  </body>
</html>

у кімнаті пайтон така сама верска тільки інша назва змінної room

Last updated