Práctica 4: Home chat - Sianats/LTAW-Practicas GitHub Wiki

Práctica 4: Electron: Home chat

Índice

Introducción

El objetivo de esta práctica es convertir el servidor de Chat de la práctica 3 en una aplicación Electron nativa. Esta, tiene una interfaz gráfica que muestra la siguiente información:

  • Versión de node
  • Versión de Electron
  • Versión de Chrome
  • URL a la que se deben conectar los clientes para chatear
  • Mostrar los mensajes que llegan al servidor, del resto de usuarios
  • Botón de pruebas para enviar un mensaje a todos los clientes conectados

Documentación técnica:

Mi código de esta práctica se encuentra en mi Repositorio 4. Consta de la carpeta public de mi Práctica 3 y de tres nuevos archivos: index.html, index.js, main.js.

Front-end

Tanto en los css como en el html, hay especificaciones de qué hace cada cosa. Por lo que solo me queda enseñar el resultado estético. Al entrar en el servidor, Aparece lo siguiente:

Al acceder, cambia el número de usuarios y aparece el servidor, estéticamente igual al de mi práctica 3:

Y, por último, si pulsas el botón aparece un mensaje de prueba enviado por el servidor:

Back-end

Adjunto mi código, con sus funciones explicadas una a una en los comentarios del propio:

  • Código de mi fichero index.js:
const electron = require('electron');

console.log("Hola desde el proceso de la web...");

//-- Obtener elementos de la interfaz
const btn_test = document.getElementById("btn_test");
const display = document.getElementById("display");
const info1 = document.getElementById("info1");
const info2 = document.getElementById("info2");
const info3 = document.getElementById("info3");
const node = document.getElementById("node");
const chrome = document.getElementById("chrome");
const electron1 = document.getElementById("electron1");
const ip1 = document.getElementById("ip1");
const numus = document.getElementById("numus");

//-- Acceder a la API de node para obtener la info
//-- Sólo es posible si nos han dado permisos desde
//-- el proceso princpal
info1.textContent = process.arch;
info2.textContent = process.platform;
info3.textContent = process.cwd();
node.textContent = process.versions.node;
chrome.textContent = process.versions.chrome;
electron1.textContent = process.versions.electron;

// Se muestra la url declarada en el main
electron.ipcRenderer.on('ip', (event, msg) => {
    console.log("Recibido: " + msg);
    ip1.textContent = msg;
});

// Al pulsar en botón, aparece el mensaje
btn_test.onclick = () => {
    console.log("Botón apretado");
    //-- Enviar mensaje al proceso principal
    electron.ipcRenderer.invoke('test', "Boton de prueba... funciona :)");
}

// Enseña el número de usuarios conectados
electron.ipcRenderer.on('numus', (event, msg) => {
    console.log("Usuarios: " + msg);
    numus.textContent = msg;
});

//-- Mensaje recibido del proceso MAIN
electron.ipcRenderer.on('display', (event, msg) => {
    console.log("Recibido: " + msg);
    if(!msg.includes(' se ha unido</h5>')){
        display.innerHTML += '<p class="mess mess-r" style="text-align: right";>' + msg + '</p>';
        } else {
          // Si aparece ese mensaje en el texto, no declaro ninguna clase o estilo definido
          //(es puramente estético. Solo es css, no tiene funcionalidad js).
          display.innerHTML += '<p>' + msg + '</p>';
        }
});
  • Código de mi fichero main.js:
//-- Cargar las dependencias
const socketServer = require('socket.io').Server;
const http = require('http');
const express = require('express');
const colors = require('colors');
const electron = require ('electron');
const ip = require('ip');

const PUERTO = 9090;

//-- Crear una nueva aplciacion web
const app = express();

let win = null;

//-- Crear un servidor, asosiaco a la App de express
const server = http.Server(app);

//-- Crear el servidor de websockets, asociado al servidor http
const io = new socketServer(server);

//-------- PUNTOS DE ENTRADA DE LA APLICACION WEB
//-- Definir el punto de entrada principal de mi aplicación web
app.get('/', (req, res) => {
  let path = __dirname + 'public/chat.html';
  res.sendFile(path);
});

//-- Esto es necesario para que el servidor le envíe al cliente la
//-- biblioteca socket.io para el cliente
app.use('/', express.static(__dirname +'/'));

//-- El directorio publico contiene ficheros estáticos
app.use(express.static('public'));

//Establezco un valor predeterminado para la variable num
let num = 0;

//------------------- GESTION SOCKETS IO
//-- Evento: Nueva conexion recibida
io.on('connect', (socket) => {
  console.log('** NUEVA CONEXIÓN **'.yellow);
  // Mensaje de bienvenida al chat
  socket.write('¡Bienvenido al chat de ISAM!');
  // El numero de usuarios aumenta 1 cada vez que alguien se conecta
  num += 1;
  win.webContents.send('numus', num);
  //-- Evento de desconexión
  socket.on('disconnect', function(){
    console.log('** CONEXIÓN TERMINADA **'.yellow);
    //Mensaje a los demás usuarios informando de que alguién abandonó el chat
    io.send('Un usuario ha abandonado el chat');
    // El número de usuarios en el servidor disminuye 1
    num -= 1;
    win.webContents.send('numus', num);
  });  

  //-- Mensaje recibido: Reenviarlo a todos los clientes conectados
  socket.on("message", (msg)=> {
    // Establezco ifs que determinan que si el mensaje incluye ese comando y no la frase ' se ha unido</h5>',
    // entonces hará una cosa u otra dependiendo del comando que le pides
    if (msg.includes('/help') && !msg.includes(' se ha unido</h5>')){
      // imprime una lista de comandos a usar y sus funciones
      socket.write('Los comandos disponibles son: <br> <strong>/help:</strong> Este mismo :) <br> <strong>/list:</strong> Devolverá el número de usuarios conectados <br> <strong>/hello:</strong> El servidor nos devolverá el saludo <br> <strong>/date:</strong> Nos devolverá la fecha');
    }else if(msg.includes('/hello') && !msg.includes(' se ha unido</h5>')){
      // Te saluda
      socket.write('¡Hola! Mucho ánimo con la carrera :)');
    }else if(msg.includes('/list') && !msg.includes(' se ha unido</h5>')){
      // Te dice el número total de usuarios conectados al servidor
      socket.write('Hay un total de ' + num + ' usuarios conectados');
    }else if(msg.includes('/date') && !msg.includes(' se ha unido</h5>')){
      // Establece la fecha
      const tiempoTranscurrido = Date.now();
      const hoy = new Date(tiempoTranscurrido);
      // Imprime la fecha, específicamente la de España, en el formato Español
      socket.write('Hoy es: ' + hoy.toLocaleString('es-ES'));
    }else if(msg.includes('/' + '') && !msg.includes(' se ha unido</h5>') && !msg.includes('/date') && !msg.includes('/list') && !msg.includes('/help') && !msg.includes('/hello') ){
      // Si usas un comando no establecido, te salta un error con el siguiente mensaje:
      socket.write('Lo siento pero no es un comando válido :(');
    }else{
      // Si lo escrito no es un comando, se imprime en el chat y en el terminal el mensaje que has escrito
        console.log("Mensaje Recibido!: " + msg.blue);
        //-- Reenviarlo a todos los clientes conectados
        io.send(msg);
    }
    // Se envía al display
    win.webContents.send('display', msg);
});

});

electron.app.on('ready', () => {
  win = new electron.BrowserWindow({
      width: 600,
      height: 600,
      // permitir acceso al sistema
      webPreferences: {
          nodeIntegration: true,
          contextIsolation: false
      }
  })
  win.loadFile("index.html");
  win.on('ready-to-show', () => {
      win.webContents.send('port', PUERTO);
  })

  // Se envía la url del usuario 
  win.on('ready-to-show', () => {
    win.webContents.send('ip', 'http://' + ip.address() + ':' + PUERTO + '/public/chat.html');
  });

});


electron.ipcMain.handle('test', (event, msg) => {
  console.log(msg);
  //-- Enviar mensaje de prueba
  io.send(msg);
  win.webContents.send('msg', msg);

});

//-- Lanzar el servidor HTTP
//-- ¡Que empiecen los juegos de los WebSockets!
server.listen(PUERTO);
console.log("Escuchando en puerto: " + PUERTO);

Manual de usuario

Para empezar a usar mi servidor y después de haberte descargado mi carpeta P4, debes ingresar los siguientes comandos (uno a uno) en el terminal de la carpeta. Asegúrate de primero haberte descargado también el fichero package.json de mi P4 (sino tendrás que crearte uno tu mismo, abajo te dejo el código del package.json que te tendrías que crear ANTES DE INTRODUCIR LOS COMANDOS):

  • npm i ip

  • npm i colors

  • npm i express

  • npm i electron

  • npm i socket.io

  • npm i (este es por si a caso)

  • Package.json:

{
    "name": "mi-electron-app",
    "description": "Estas es mi primera aplicación de escritorio en Electron",
    "version": "0.1.0",
    "main": "main.js",
    "scripts": {
        "start": "electron ."
    },
    "dependencies": {
        "electron": "^18.0.1"
    }
}

Después, solo hace falta introducir el siguiente comando para iniciarlo: npm start

Una vez en el servidor, copia el URL del usuario y pégalo en tu navegador. ¡Ahora puedes escribir mensajes y enviarlos al servidor, donde podrás hablar con más gente conectada! En el servidor te aparecerá el número de usuarios conectados (para asegurarte de que no estás hablando solo ;) ). Puedes pulsar el botón de prueba para enviar un mensaje de prueba a todos los usuarios en línea si quieres. También podrás personalizar tu nombre de usuario, como en la práctica 3.

Autores

Licencia

⚠️ **GitHub.com Fallback** ⚠️