Chat-applikation med Angular og Socket.IO

Indledning

Vi vil bruge RxJS, Angular, express (Node.js) & Socket.IO til at lave en chat-applikation. Vi vil komme til at se, hvor nyttig RxJS kan være i dette scenarie. For at gøre tingene glat og let vil vi bruge Angular CLI til at generere grundlæggende klientstruktur og få os en boilerplate til den enkleste fungerende Angular-applikation. På back-end vil vi bruge Node.js med express og Socket.IO. Begrundelsen bag dette er, at Socket.IO er meget let at sætte op og arbejde med. Desuden indeholder det både biblioteker på server- og klientsiden. Socket.IO bruger primært WebSocket-protokollen til at muliggøre bidirektionel kommunikation i realtid.

Hvis du vil springe direkte til den del, hvor vi bruger RxJS til at håndtere chatbeskederne, klik her.

Lad os komme i gang!

Socket.IO-serveropsætning

Hvis du ikke har Angular CLI installeret, kan du installere det ret nemt:

npm i -g @angular/cli

Opsætning af mappestruktur

For at holde tingene rene vil vi oprette en ny rxjs-chat-mappe til vores lille projekt. Den skal fungere som rodmappe for Angular- og Socket.IO-apps.

Lader os oprette en grundlæggende Angular-app ved hjælp af Angular CLI. I vores projektmappe starter du din foretrukne terminal og kører følgende kommando:

ng new rxjs-chat

Giv det en smule tid. Når den er færdig med at skabe den grundlæggende struktur og installere npm-pakker, omdøber vi den nyoprettede Angular-projektmappe til klient. Derefter skal vi i den samme rodmappe oprette mappen server til vores Socket.IO-server i den samme rodmappe. Nu har vi to mapper inde i vores rxjs-chat-mappe:

  • klient – Angular-klient-app
  • server – snart Node Socket.IO-server
Installation af lokale pakker

I servermappen vil vi generere pakke.json-fil ved at køre følgende kommando:

npm init -y

Dernæst installerer vi vores afhængigheder og gemmer dem i package.json:

npm install express socket.io --save

I samme mappe opretter vi index.js-filen til vores serverapp. Indholdet af filen skal være som følger:

Vi opretter en instans af express og gemmer den i app-variablen. Derefter opretter vi server med http modul. Derefter overfører vi express til http.Server()-metoden. Express vil fungere som handleren for anmodninger til vores server. Til gengæld får vi instansen af serveren, som vi gemmer i server variabel.

I de næste to kodelinjer binder vi socket.IO med vores http server:

let socketIO = require('socket.io');

let io = socketIO(server);

Efter det lytter vi efter connection event af socket.IO, og vi logger, når en bruger har etableret en forbindelse med serveren. Til sidst starter vi serveren og lytter på en given port, i vores tilfælde er det port 3000.

Lader os faktisk starte vores server ved at køre følgende i servermappen:
node index.js
Derpå bør du få følgende besked: “started on port: 3000”.

Opkobling til Socket.IO

Vi har en server, der kører på port 3000. Nu er det tid til at se, hvordan vi kan oprette forbindelse til serveren fra vores Angular-app. Til dette skal vi installere Socket.IO-klientbiblioteket. Vi kører følgende kommando i vores klientmappe:

npm install socket.io-client --save

Mens vi er i gang, så lad os køre Angular-appen via Angular CLI:

ng serve -o

Nu har vi fået vores app til at køre. Vi kan se, at vores standardbrowser lige har åbnet en ny fane, der peger på localhost. Det er derfor, vi brugte -o-argumentet til at åbne browseren.

Skabelse af tjeneste til kommunikation med server

Jeg vil kalde den chat.service.ts app.chat.service.ts og placere den inde i src-mappen. Tjenesten vil være så enkel som muligt for nu:

Tilføjelse af tjenesten til modulets udbydere

Lader os også tilføje vores ChatService til listen over udbydere inde i AppModule i app.module.ts-filen:

Injicering af tjenesten i vores komponent

Sluttelig vil vi importere og bruge tjenesten inde i vores app.component.ts-fil:

import { ChatService } from './app.chat.service';

Og vi vil injicere ChatService i vores konstruktør:

constructor(chatService: ChatService) { }

Som et resultat har vi følgende fil:

Hvis alt gik som forventet efter at have gemt ændringerne, bør du se meddelelsen ‘user connected’ i den terminal, hvor du startede node app:

$ node index.js
started on port: 3000
user connected

Dermed kan vi sige, at det endelig lykkedes os at oprette forbindelse til vores Socket IO-server. Nu er det tid til rent faktisk at sende nogle data via Socket IO-hændelser.

Sending a message to Socket.IO

Tid til at forbedre vores hidtil simple ChatService med en mulighed for at sende en besked til serveren:

For at dette kan fungere, skal vi bruge sendMessage() fra vores AppComponent:

Endeligt skal vi give brugeren et simpelt tekstinput og en knap, så han kan sende en besked:

For at det hele skal fungere, skal vi lytte på serveren efter ‘new-message’-begivenheden, som vi udsendte fra ChatService:

socket.on('new-message', (message) => {
console.log(message);
});

Nu skal vores indeks.js ser således ud:

Hvis du vil lege med koden, kan du finde den på min GitHub-repo – rxjs-chat.

Kommunikation med andre brugere

For at vores besked kan blive udsendt til andre brugere, skal vi blot ændre console.log(message) inden for vores ‘new-message’-event callback til io.emit(message):

Og hvad gør io.emit()? Med enkle ord sender den en begivenhed til alle, der er forbundet til serveren.

Lader os kommunikere med vores server via ChatService. Vi vil tilføje en ny metode til vores tjeneste til dette formål – getMessages. Den vil returnere en Observable, som vi vil oprette med Observable.create()-metoden. Hver gang socket modtager nye meddelelser, bruger vi observer.next() til at videresende dem til observatører.

Derpå abonnerer vi på denne Observable fra vores AppComponent:

Vi har oprettet et nyt messages array, hvor vi gemmer meddelelser modtaget fra serveren. Vi bliver nødt til at vise disse meddelelser i vores skabelon. Det er et perfekt anvendelsestilfælde for ngFor: