Menu

Aplicaciones en tiempo real con TypeScript: integración de sockets web, nodo y angular

Construyendo una aplicación de chat en tiempo real desde cero usando TypeScript

El objetivo principal era escribir una demostración para explicar cómo puede utilizar este lenguaje de programación en el lado del cliente y en el servidor. La aplicación cliente está utilizando las últimas características de Angular.

¿Qué es una aplicación en tiempo real?

De acuerdo con esta definición de Wikipedia , una aplicación en tiempo real permite que la información se reciba tan pronto como se publica , en lugar de requerir que una fuente sea revisada periódicamente para actualizaciones. Por lo tanto, este tipo de aplicación debería dar a los usuarios la sensación de que los eventos y las acciones suceden inmediatamente.

Websockets

WebSockets es un protocolo que proporciona un canal de comunicación bidireccional. Esto significa que un navegador y un servidor web pueden mantener comunicaciones en tiempo real, enviando mensajes de ida y vuelta mientras la conexión está abierta.

Estructura de la aplicación

Separaremos el código relacionado con el servidor y el código del cliente. Entraré en detalles cuando se expliquen los archivos más importantes. Por ahora, esta es la estructura esperada de nuestra aplicación:

servidor /
| – src /
| – package.json
| – tsconfig.json
| – gulpfile.js

cliente /
| – src /
| – package.json
| – tsconfig.json
| – .angular-cli.json

Código del servidor

Dado que WebSockets es una especificación , podemos encontrar varias implementaciones al respecto. Podemos elegir TypeScript o cualquier otro lenguaje de programación.

En este caso, usaremos Socket.IO , que es uno de los motores en tiempo real más rápidos y confiables.

Inicializando la aplicación del servidor

Crea un package.json archivo y luego instala las siguientes dependencias:

npm install –save express socket.io @ types / express @ types / socket.io

Necesitaremos instalar algunos devDependenciespara permitir la integración gulpy typescriptpara poder definir las tareas de compilación fácilmente con estas herramientas más adelante:

npm install –save-dev typescript gulp gulp-typescript

Configuración del compilador de TypeScript

Crea un tsconfig.jsonarchivo con el siguiente contenido:

{
files: [
src/*.ts,
src/model/*.ts
],
compilerOptions: {
target: es5
}
}

Definición del modelo de datos

Aprovechando la escritura estática, definamos un pequeño modelo de datos de la siguiente manera:

export class User {

constructor(private name: string) {}

}
export class Message {
constructor(private from: User, private content: string) {}
}
export class ChatMessage extends Message{
constructor(from: User, content: string) {
super(from, content);
}
}

..le vea más detalles en nuestro server/srcdirectorio:

server /
| – src /
| – model /
| – message.model.ts
| – user.model.ts
| – index.ts
| – server.ts
| – package.json
| – tsconfig.json
| – gulpfile.js

Implementación del servidor de chat

Los archivos principales en el serverdirectorio son index.tsy chat-server.ts. La primera nos permite crear y exportar nuestra ChatServeraplicación, mientras que la última contiene configuraciones Express y socket.IO :

import { createServer, Server } from http;

import * as express from express;

import * as socketIo from socket.io;
import { Message } from ./model;
export class ChatServer {
public static readonly PORT:number = 8080;
private app: express.Application;
private server: Server;
private io: SocketIO.Server;
private port: string | number;
constructor() {
this.createApp();
this.config();
this.createServer();
this.sockets();
this.listen();
}
private createApp(): void {
this.app = express();
}
private createServer(): void {
this.server = createServer(this.app);
}
private config(): void {
this.port = process.env.PORT || ChatServer.PORT;
}
private sockets(): void {
this.io = socketIo(this.server);
}
private listen(): void {
this.server.listen(this.port, () => {
console.log(Running server on port %s, this.port);
});
this.io.on(connect, (socket: any) => {
console.log(Connected client on port %s., this.port);
socket.on(message, (m: Message) => {
console.log([server](message): %s, JSON.stringify(m));
this.io.emit(message, m);
});
socket.on(disconnect, () => {
console.log(Client disconnected);
});
});
}
public getApp(): express.Application {
return this.app;
}
}

Clases de servidor

El código anterior dará un resultado de las siguientes clases y relaciones:

Diagrama de clases del servidor

 

Construir y ejecutar el servidor

Para tener los archivos JavaScript que necesita el motor V8 de Node.js, podemos agregar una buildtarea a nuestro gulpfile.jsarchivo:

var gulp = require ( gulp );

var ts = require ( gulp-typescript );

var tsProject = ts . createProject ( tsconfig.json );
tragar . tarea ( build , function () {
devuelve tsProject . src ()
. pipe ( tsProject ())
. js . pipe ( gulp . dest ( ./dist ));
});

Como puede ver, la salida del proceso de compilación (archivos JavaScript) se ubicará en el distdirectorio. Para realizar esta acción, necesitarás ejecutar:

construir trago

Ahora podemos ejecutar el node dist/index.jscomando para que el servidor se ejecute.

Código del cliente

Generemos nuestro clientdirectorio utilizando la última versión de Angular CLI :

Nuevo cliente mecanografiado de chat –routing –prefix tcc –skip-install

Luego instale sus dependencias en ejecución npm install(prefiero usar Yarnpara este paso) :

cd typescript-chat-client
instalación de hilos

Añadiendo material angular

Encuentre y siga la guía más reciente para instalar material angular dentro de su Angular CLIproyecto.

Como parte del uso de las mejores prácticas en la estructura de nuestro proyecto , podemos crear sharedy materialmódulos:

cliente /
| – src /
| – app /
| – chat /
        | – shared /
| – material /
| – material.module.ts
| – shared.module.ts

| -app.module.ts

Podemos hacerlo desde la interfaz de línea de comandos:

ng generar módulo compartido – aplicación de
módulo ng generar módulo compartido / material – módulo compartido

Compruebe los cambios en el interior app.module.tsy shared.module.tspara ver las relaciones creadas entre estos módulos.

Añadiendo express y socket.IO

Tendremos que agregar expressy socket.iomódulos en nuestra aplicación cliente:

npm instalar Express socket.io –save

Módulos de chat y componentes

Creemos un nuevo módulo antes de comenzar a crear componentes para nuestra aplicación de chat:

ng generar módulo de chat – aplicación de módulo

Ahora agregue un componente en el módulo más nuevo:

ng generar chat componente – chat módulo

Para usar sockets web y modelos personalizados, creemos otra sharedcarpeta. Esta vez dentro del chatdirectorio:

ng generar servicio chat / shared / services / socket –module chat
ng generar clase chat / shared / model / user
ng generar clase chat / shared / model / message

Estaremos terminando con una estructura similar a:

cliente /
| – src /
| – app /
| – chat /
          | – shared /
| – model /
| – user.ts
| – message.ts
| – services /
| – socket.service.ts

| – shared /
| -app .module.ts

Observables y sockets web

Ya que nuestra aplicación Angular viene con RxJS, podemos usar Observablespara capturar eventos Socket.IO:

import { Injectable } from @angular/core;

import { Observable } from rxjs/Observable;

import { Observer } from rxjs/Observer;
import { Message } from ../model/message;
import { Event } from ../model/event;
import * as socketIo from socket.io-client;
const SERVER_URL = http://localhost:8080;
@Injectable()
export class SocketService {
private socket;
public initSocket(): void {
this.socket = socketIo(SERVER_URL);
}
public send(message: Message): void {
this.socket.emit(message, message);
}
public onMessage(): Observable<Message> {
return new Observable<Message>(observer => {
this.socket.on(message, (data: Message) => observer.next(data));
});
}
public onEvent(event: Event): Observable<any> {
return new Observable<Event>(observer => {
this.socket.on(event, () => observer.next());
});
}
}

Tendremos que definir algunas enumeraciones para administrar Actions y Eventsen la aplicación:

// Actions you can take on the App

export enum Action {

JOINED,
LEFT,
RENAME
}
// Socket.io events
export enum Event {
CONNECT = connect,
DISCONNECT = disconnect
}

Ahora estamos listos para escuchar los mensajes del servidor:

import { Component, OnInit } from @angular/core;
import { Action } from ./shared/model/action;
import { Event } from ./shared/model/event;
import { Message } from ./shared/model/message;
import { User } from ./shared/model/user;
import { SocketService } from ./shared/services/socket.service;
@Component({
selector: tcc-chat,
templateUrl: ./chat.component.html,
styleUrls: [./chat.component.css]
})
export class ChatComponent implements OnInit {
action = Action;
user: User;
messages: Message[] = [];
messageContent: string;
ioConnection: any;
constructor(private socketService: SocketService) { }
ngOnInit(): void {
this.initIoConnection();
}
private initIoConnection(): void {
this.socketService.initSocket();
this.ioConnection = this.socketService.onMessage()
.subscribe((message: Message) => {
this.messages.push(message);
});
this.socketService.onEvent(Event.CONNECT)
.subscribe(() => {
console.log(connected);
});
this.socketService.onEvent(Event.DISCONNECT)
.subscribe(() => {
console.log(disconnected);
});
}
public sendMessage(message: string): void {
if (!message) {
return;
}
this.socketService.send({
from: this.user,
content: message
});
this.messageContent = null;
}
public sendNotification(params: any, action: Action): void {
let message: Message;
if (action === Action.JOINED) {
message = {
from: this.user,
action: action
}
} else if (action === Action.RENAME) {
message = {
action: action,
content: {
username: this.user.name,
previousUsername: params.previousUsername
}
};
}
this.socketService.send(message);
}
}

Una vez que ChatComponentse inicializa, el componente se suscribirá a los SocketServiceobservables para comenzar a recibir eventos de conexión o mensajes entrantes.

Las funciones sendMessagey sendNotificationvan a enviar el contenido respectivo a través del mismo servicio. Las notificaciones enviadas en este momento son Cambiar nombre de usuario y Usuario unido.

Características de la aplicación de chat

  • CLI angular
  • Angular 5
  • Material angular

El código se puede encontrar en : github.com/luixaviles/socket-io-typescript-chat

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *