Aplikacja czatowa z Angular i Socket.IO
Wprowadzenie
Użyjemy RxJS, Angular, express (Node.js) & Socket.IO do stworzenia aplikacji czatowej. Przekonamy się jak przydatny może być RxJS w tym scenariuszu. Aby wszystko było gładkie i łatwe będziemy używać Angular CLI do generowania podstawowej struktury klienta i uzyskania boilerplate dla najprostszej działającej aplikacji Angular. Na back-end użyjemy Node.js z express i Socket.IO. Powodem tego jest to, że Socket.IO jest bardzo łatwy do skonfigurowania i pracy z nim. Co więcej, dostarcza zarówno biblioteki po stronie serwera jak i klienta. Socket.IO przede wszystkim wykorzystuje protokół WebSocket, aby umożliwić dwukierunkową komunikację w czasie rzeczywistym.
Jeśli chcesz przeskoczyć bezpośrednio do części, w której używamy RxJS do obsługi wiadomości czatu, kliknij tutaj.
Zaczynamy!
Socket.IO
Jeśli nie masz zainstalowanego Angular CLI, możesz go zainstalować w bardzo prosty sposób:
npm i -g @angular/cli
Ustaw strukturę folderów
Aby zachować porządek, utworzymy nowy folder rxjs-chat dla naszego małego projektu. Powinien on służyć jako folder główny dla aplikacji Angular i Socket.IO.
Utwórzmy podstawową aplikację Angular używając Angular CLI. W naszym folderze projektu uruchom swój ulubiony terminal i wykonaj następującą komendę:
ng new rxjs-chat
Daj jej trochę czasu. Po zakończeniu tworzenia podstawowej struktury i zainstalowaniu pakietów npm zmienimy nazwę nowo utworzonego folderu projektu Angular na client. Następnie w tym samym folderze głównym tworzymy folder server dla naszego serwera Socket.IO. Teraz mamy dwa foldery wewnątrz naszego folderu rxjs-chat:
- klient – Angularowa aplikacja kliencka
- serwer – wkrótce będzie to Node’owy serwer Socket.IO
Instalacja lokalnych pakietów
W folderze serwera wygenerujemy plik package.json wykonując następującą komendę:
npm init -y
Po tym zainstalujemy nasze zależności i zapiszemy je w pliku package.json:
npm install express socket.io --save
W tym samym folderze utworzymy plik index.js dla naszej aplikacji serwerowej. Zawartość pliku powinna być następująca:
Tworzymy instancję express i przechowujemy ją w zmiennej app
. Następnie tworzymy serwer z modułem http
. Następnie przekazujemy express
do metody http.Server()
. Express będzie służył jako handler dla żądań do naszego serwera. W zamian otrzymujemy instancję serwera, którą przechowujemy w zmiennej server
.
W kolejnych dwóch liniach kodu wiążemy socket.IO z naszym http server:
let socketIO = require('socket.io');
let io = socketIO(server);
node index.js
Connecting to Socket.IO
Mamy serwer działający na porcie 3000. Teraz czas zobaczyć jak możemy połączyć się z serwerem z naszej Angularowej aplikacji. W tym celu będziemy musieli zainstalować bibliotekę kliencką Socket.IO. Uruchomimy następujące polecenie w naszym folderze klienta:
npm install socket.io-client --save
While we are at it lets run the Angular app via Angular CLI:
ng serve -o
Now we got our app running. Możemy zobaczyć, że nasza domyślna przeglądarka właśnie otworzyła nową kartę wskazującą na localhost. Dlatego właśnie użyliśmy argumentu -o
do otwarcia przeglądarki.
Tworzenie usługi do komunikacji z serwerem
Nazwę ją chat.service.ts app.chat.service.ts i umieszczę ją wewnątrz folderu src. Usługa będzie na razie tak prosta, jak to tylko możliwe:
Dodanie usługi do dostawców modułu
Dodajemy również naszą usługę ChatService do listy dostawców wewnątrz modułu AppModule w pliku app.module.ts:
Wstrzyknięcie usługi do naszego komponentu
Na koniec, zaimportujemy i użyjemy usługi wewnątrz naszego app.component.ts:
import { ChatService } from './app.chat.service';
I wstrzykniemy ChatService w naszym konstruktorze:
constructor(chatService: ChatService) { }
W rezultacie mamy następujący plik:
Jeśli wszystko poszło zgodnie z oczekiwaniami po zapisaniu zmian powinieneś zobaczyć komunikat 'user connected’ w terminalu, w którym uruchomiłeś node app:
$ node index.js
started on port: 3000
user connected
Więc możemy powiedzieć, że w końcu udało nam się połączyć z naszym serwerem Socket IO. Teraz nadszedł czas, aby faktycznie wysłać jakieś dane za pomocą zdarzeń Socket IO.
Wysyłanie wiadomości do Socket.IO
Czas wzbogacić naszą jak dotąd prostą usługę ChatService o opcję wysyłania wiadomości do serwera:
Aby to zadziałało, musimy użyć sendMessage()
z naszego AppComponent:
Na koniec, dajmy użytkownikowi proste wejście tekstowe i przycisk, aby mógł wysłać wiadomość:
Aby to wszystko działało musimy nasłuchiwać na serwerze na zdarzenie 'new-message’, które wyemitowaliśmy z ChatService:
socket.on('new-message', (message) => {
console.log(message);
});
Teraz nasz index.js wygląda tak:
Jeśli chcesz pobawić się kodem, możesz go znaleźć w moim repo na GitHubie – rxjs-chat.
Komunikowanie się z innymi użytkownikami
Aby nasza wiadomość została rozesłana do innych użytkowników, wszystko co musimy zrobić, to zmienić console.log(message)
wewnątrz naszego wywołania zwrotnego zdarzenia 'new-message’ na io.emit(message)
:
A co robi io.emit()? W prostych słowach wysyła zdarzenie do wszystkich podłączonych do serwera.
Komunikujmy się z naszym serwerem poprzez ChatService. W tym celu dodamy do naszej usługi nową metodę – getMessages
. Będzie ona zwracała Observable, którą utworzymy za pomocą metody Observable.create()
. Za każdym razem, gdy socket otrzyma nową wiadomość, użyjemy metody observer.next() aby przekazać ją do obserwatorów.
Potem zasubskrybujemy tę Observable z naszego AppComponentu:
Utworzyliśmy nową messages
array, w której będziemy przechowywać wiadomości otrzymane z serwera. Będziemy musieli pokazać te wiadomości w naszym szablonie. To jest idealny przypadek użycia dla ngFor:
.