3.1 Tworzymy czat
Przeanalizujmy utworzenie prostego czatu przy pomocy biblioteki Socket.io. To nasz przykład, który będziemy rozpatrywać - Chat example
Realizacja części serwerowej jest dość prosta:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
server.listen(process.env.PORT || 3000, function () {
console.log('Server running in port 3000');
});
app.use(express.static(__dirname + '/public'));
Podłączamy wszystkie niezbędne moduły, uruchamiamy serwer i wskazujemy, gdzie będą znajdować się zasoby statystyczne, w naszym przypadku strona html i skrypty związane z zachowaniem klienta.
Następnie tworzymy obiekt:
const users = {};
będziemy tam zapisywać, zgodnie z unikalnym kluczem klienta, nazwę dla każdego podłączanego użytkownika.
Cała praca czatu będzie zamknięta wewnątrz konstrukcji:
io.sockets.on('connection', (client) => { … })
Ten kod wykona się dla każdego nowo podłączanego użytkownika w zdarzeniu connection.
Wewnątrz tworzymy funkcję:
const broadcast = (event, data) => {
client.emit(event, data);
client.broadcast.emit(event, data);
};
Ta funkcja wykonuje zdarzenie event i przesyła dane data konkretnie dla bieżącego użytkownika client.emit(event, data), następnie inicjuje zdarzenie dla wszystkich pozostałych podłączonych użytkowników client.broadcast.emit(event, data).
Przy pierwszym podłączeniu danego użytkownika wykonujemy zdarzenie user
broadcast('user', users);
i powiadamiamy wszystkich uczestników czatu o naszej aktualnej liście użytkowników.
Przydadzą się nam jeszcze dwie funkcje dla zdarzeń
- message - wysłanie wiadomości na czacie
- disconnect - użytkownik wyszedł z czatu (zamknął zakładkę przeglądarki).
Wysłanie wiadomości:
client.on('message', message => {
if (users[client.id] !== message.name) {
users[client.id] = message.name;
broadcast('user', users);
}
broadcast('message', message);
});
Sprawdzamy, czy użytkownik jest już na liście users czy też zmienił nazwę przy wysłaniu wiadomości i jeśli tak, to następnie informujemy wszystkich użytkowników przez zdarzenie user, że dany użytkownik zmienił swoją nazwę. Później wywołujemy zdarzenie message i wysyłamy otrzymaną wiadomość do wszystkich użytkowników.
Jeżeli użytkownik zaktualizował stronę lub zamknął zakładkę przeglądarki nastąpi zdarzenie disconnect.
client.on('disconnect', () => {
delete users[client.id];
client.broadcast.emit('user', users);
});
Usuwamy bieżącego użytkownika z listy users i wysyłamy do wszystkich pozostałych użytkowników przez zdarzenie user zaktualizowaną listę. Zwróć uwagę, że wysyłamy to zdarzenie tylko do pozostałych użytkowników. Na nasze potrzeby to wszystko co potrzebujemy po stronie serwera
Kod klienta jest bardziej skomplikowany.
Tworzymy zmienne ze wszystkimi niezbędnymi dla DOM elementami:
const usersList = document.getElementById('users');
const board = document.getElementById('board');
const userMessage = document.getElementById('msg_txt');
const userName = document.getElementById('msg_name');
const sendButton = document.getElementById('msg_btn');
Podłączamy socket.io:
const socket = io();
Tworzymy tablicę, w której będziemy zapisywać otrzymane od serwera wiadomości:
const messages = [];
i ustawiamy limit dla maksymalnej ilości wiadomości na ekranie:
const LIMIT_MESSAGES = 10;
Funkcja renderListOfMessages za każdym razem po otrzymaniu zdarzenia message rysuje zaktualizowaną listę wiadomości od użytkowników na stronie.
Funkcja renderListOfUsers za każdym razem przy otrzymaniu zdarzenia user rysuje zaktualizowaną listę użytkowników na stronie.
Za podłączenie handlers do odpowiednich zdarzeń odpowiada następujący fragment kodu:
socket.on('user', renderListOfUsers);
socket.on('message', renderListOfMessages);
Samo wysłanie wiadomości na serwer wykonuje się w funkcji sendUserMessage.
const sendUserMessage = () => {
let name = userName.value;
const message = userMessage.value;
if (message === '' || name === '') {
return;
}
socket.emit('message', {
message,
name,
});
userMessage.value = '';
userMessage.focus();
};
sendButton.addEventListener('click', sendUserMessage);
Funkcja
const pressEnterKey = e => {
if (e.keyCode === 13) {
sendUserMessage();
}
};
będzie wywoływać funkcję sendUserMessage, jeżeli naciśniemy klawisz Enter.
Jak widać, cała logika pracy kodu klienta zbudowana jest na obsługiwaniu zdarzeń user i message, które generuje dla nas serwer, a także generowaniu zdarzenia message które służy do wysyłania na serwer wiadomości (funkcja sendUserMessage).