O projekcie

Analiza wymagań

Standardowy czat: użytkownik wysyła komunikat, który serwer rozsyła do wszystkich połączonych użytkowników.

Aplikacja została zaimplementowana w oparciu o protokół Websocket z wykorzystaniem modułu Socket.IO

Struktura plików

Struktura plików aplikacji podana jest na poniższym obrazku.

.
├── Gruntfile.js
├── package.json
├── public
│   ├── css
│   │   └── styl.css
│   ├── img
│   │   ├── bullet_green.png
│   │   └── bullet_red.png
│   ├── index.html
│   └── js
│       └── skrypt.js
└── serwer.js

Główne pliki w tej implementacji — to: index.html,script.js, serwer.js.

index.html

Ten plik jest wysyłany do klienta bez zmian. Zawiera on podstawowe drzewo DOM strony. Drzewo to będzie uzupełniane i modyfikowane dynamiczne po stronie klienta.

script.js

Ten plik zawiera aplikację kliencką.

serwer.js

W tym pliku jest aplikacja serwerowa.

Plik serwer.js

W aplikacji utworzono dwa serwery: standardowy HTTP oraz serwer Websocket[1]

var express = require('express');
var app = express();
var httpServer = require("http").Server(app);
var io = require("socket.io")(httpServer);

Przy połączeniu (zdarzenie connection) na obiekcie socket, który odpowiada klientowi, rejestruje się dwa callbacki: na zdarzenie message (komunikat od klienta) oraz zdarzenie error.

io.sockets.on("connection", function (socket) {
    socket.on("message", function (data) {
        io.sockets.emit("echo", "No tak, tak – dostałem: " + data);
    });
    socket.on("error", function (err) {
        console.dir(err);
    });
});

Plik script.js

W momencie, kiedy drzewo DOM już jest zbudowano, wywołana jest funkcja, wykonująca następujące czynności:

  1. Otrzymuje dostęp do elementów DOM poprzez odpowiednie zmienne:

    var status = document.getElementById("status");
    var open = document.getElementById("open");
    var close = document.getElementById("close");
    var send = document.getElementById("send");
    var text = document.getElementById("text");
    var message = document.getElementById("message");
    
  2. Określa obiekt socket, który będzie odpowiadał za połączenie z serwerem:

    var socket;
    
  3. Ustawia początkowe właściwości elementów DOM:

    status.textContent = "Brak połącznia";
    close.disabled = true;
    send.disabled = true;
    
  4. Po kliknięciu na przycisk „Połącz” (element open) nawiązuje się nowe połączenie Websocket:

        open.addEventListener("click", function (event) {
            open.disabled = true;
            if (!socket || !socket.connected) {
                socket = io({forceNew: true});
            }
    

    Oraz ustawia się callbacki na zdarzenia:

    1. connect — zmiana ustawień elementów:

          socket.on('connect', function () {
              close.disabled = false;
              send.disabled = false;
              status.src = "img/bullet_green.png";
              console.log('Nawiązano połączenie przez Socket.io');
          });
      
    2. disconnect — przywrócenie ustawień elementów:

          socket.on('disconnect', function () {
              open.disabled = false;
              status.src = "img/bullet_red.png";
              console.log('Połączenie przez Socket.io zostało zakończone');
          });
      
    3. error — wyświetlenie komunikatu o błędzie:

          socket.on("error", function (err) {
              message.textContent = "Błąd połączenia z serwerem: '" 
      			      + JSON.stringify(err) + "'";
          });
      
    4. echo — wyświetlenie komunikatu, otrzymanego z serwera:

          socket.on("echo", function (data) {
              message.textContent = "Serwer twierdzi, że otrzymał od Ciebie: '" 
      			      + data + "'";
          });
      
  5. Po kliknięciu na przycisk „Rozłącz” (element close) połączenia się rozłącza i stosownie zmienia się ustawienia:

        close.addEventListener("click", function (event) {
            close.disabled = true;
            send.disabled = true;
            open.disabled = false;
            message.textContent = "";
            socket.io.disconnect();
            console.dir(socket);
        });
    
  6. Po kliknięciu na przycisk „Wyślij” (element send) wysyła się tekst komunikatu na serwer.

        send.addEventListener("click", function (event) {
            socket.emit('message', text.value);
            console.log('Wysłałem wiadomość: ' + text.value);
            text.value = "";
        });
    

    Na serwerze dla tego klienta odpala się zdarzenie message — wynika to z powyższego kodu.

  7. Nawias zamykający funkcji:

    });
    

Szablon strony głównej (index.html)

W tym pliku są umieszczone tylko puste elementy HTML, które zostaną uzupełniane dynamicznie.



[1] Moduł Socket.IO emuluje protokół Websocket dla przeglądarek, które nie obsługują tego protokołu. Jednak takie przeglądarki są bardzo rzadkie.