EzyFox Server là một socket server framework nằm trong hệ sinh thái framework mã nguồn mở ezyfox do tổ chức mã nguồn mở Young Monkesy Việt Nam phát triển. EzyFox Server hỗ trợ cả 3 giao thức TCP, UDP và Websoket, trong bài này chúng ta sẽ cùng sử dụng thư viện ezyfox-server-es6-client để tạo ra một ứng dụng ReactJS đơn giản sử dụng websocket nhé.

Chuẩn bị

Để có thể khởi chạy được dự án ezyfox-server bạn sẽ cần:

  1. Cài đặt JDK 8 hoặc JDK 11.
  2. Cài đặt maven.
  3. Cài đặt IntelliJ, bạn có thể tải phiên bản cộng đồng nếu không có license.

Khởi tạo dự án

Bạn có thể khởi tạo thư mục cha có tên: websocket-ezyfox-server sau đó là khởi tạo dự án server và client.

Khởi tạo dự án server

Bạn có thể di chuyển vào thư mục websocket-ezyfox-server, sau đó gõ lệnh sau:

mvn archetype:generate \
    -DgroupId="vn.techmaster" \
    -DartifactId="hello-ezyfox-server" \
    -Dpackage="vn.techmaster.hello_ezyfox_server" \
    -DarchetypeGroupId="com.tvd12" \
    -DarchetypeArtifactId="ezyfox-server-archetype" \
    -DarchetypeVersion="1.3.3" \
    -DinteractiveMode=false

Lúc này một thư mục có tên hello-ezyfox-server sẽ được tạo ra, bạn có thể mở IntelliJ lên sau đó mở đến thư mục hello-ezyfox-server, kết quả bạn sẽ nhận được là cấu trúc thư mục dự án trên IntelliJ như sau:

Bạn cũng không cần quá quan tâm đến dự án server này vì chúng ta đang viết loạt bài về ReactJS. Tuy nhiên bạn cũng cần vào File > Project Structure… để chỉnh jdk của dự án sang java 8 hoặc java 11.

Khởi tạo dự án client

Đầu tiên chúng ta sẽ khởi tạo dự án client bằng cách sử dụng câu lệnh:

yarn create vite client

Bạn đừng quên lựa chọn framework là ReactJS và ngôn ngữ là Typescript nhé.
Sau khi bạn khởi tạo dự án xong hãy cd vào thư mục client vừa được tạo và gõ lệnh yarn để tải các thư viện cần thiết.
Bạn sẽ cần cài đặt thư viện ezyfox-es6-client thôn gqua câu lệnh.

npm i ezyfox-es6-client

Sau đó hãy chạy lệnh yarn dev để khởi chạy server và bạn có thể truy cập vào trang web thông qua địa chỉ: http://localhost:5173/

Khởi tạo websocket client

Đầu tiên chúng ta sẽ cần khởi tạo các đối tượng xử lý sự kiện và dữ liệu như sau:

const handshakeHandler = new Ezy.HandshakeHandler();
handshakeHandler.getLoginRequest = function () {
    return ["hello-ezyfox-server", "techmaster", "123456", []];
};

const loginSuccessHandler = new Ezy.LoginSuccessHandler();
loginSuccessHandler.handleLoginSuccess = function () {
    let accessAppRequest = ["hello-ezyfox-server", []];
    this.client.send(Ezy.Command.APP_ACCESS, accessAppRequest);
};

const accessAppHandler = new Ezy.AppAccessHandler();
accessAppHandler.postHandle = function (app: any, data: any) {
  setStatus("App accessed: " + app + ", data: " + data);
};

Ở đây chúng ta:

  1. Khởi tạo đối tượng handshakeHandler để handle sự kiện client bắt tay với server thành công, ở bước này chúng ta sẽ gửi yêu cầu login đến server đến zone hello-ezyfox-server với tên đăng nhập là techmaster và mật khẩu là 123456.
  2. Khởi tạo đối tượng loginSuccessHandler để handle sự kiện login thành công. Nếu tên đăng nhập và mật khẩu hợp lệ thì ezyfox server sẽ trả về cho bạn command login thành công, ở bước này bạn sẽ gửi yêu cầu tham gia vào một ứng dụng trên ezyfox server có thên hello-ezyfox-server.
  3. EzyFox server sẽ kiểm tra, nếu hợp lệ thì sẽ cho client vào app, lúc này bạn sẽ cần tạo đối tượng accessAppHandler để handle sự kiện vào app thành công.
    Tôi tin đến đây bạn sẽ chưa hiểu lắm về các khái niệm handshake, access app, zone, app, bạn có thể đọc hướng dẫn chính thức từ trang của Young Monkeys hoặc tiếp tục theo dõi các bài viết sau mình sẽ giải thích chi tiết hơn nhé, websocket cũng không dễ hiểu lắm do bản chất phức tạp của nó nên chúng ta sẽ cần tiếp cận dần dần.
    Sau khi đã có các đối tượng handle sự kiện và dữ liệu giờ là lúc chúng ta có thể khởi tạo websocket client với mã nguồn như sau:
var config = new Ezy.ClientConfig;
config.zoneName = "hello-ezyfox-server";
var clients = Ezy.Clients.getInstance();
var client = clients.newDefaultClient(config);
let setup = client.setup;
setup.addDataHandler(Ezy.Command.HANDSHAKE, handshakeHandler);
setup.addDataHandler(Ezy.Command.LOGIN, loginSuccessHandler);
setup.addDataHandler(Ezy.Command.APP_ACCESS, accessAppHandler);
return client;

Ở đây chúng ta đang tạo ra đối tượng client để kết nối đến zone hello-ezyfox-server của ezyfox server, chúng ta sẽ gắn các đối tượng handler với các sự kiện. Bản chất đây là một trong những ứng dụng của command design pattern.
Mã nguồn đầy đủ của tập tin App.tsx như sau:

import { useMemo, useState } from 'react';
import Ezy from 'ezyfox-es6-client';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';

function App() {
  const [status, setStatus] = useState('')

  const websocketClient = useMemo(() => {
    const handshakeHandler = new Ezy.HandshakeHandler();
    handshakeHandler.getLoginRequest = function () {
        return ["hello-ezyfox-server", "techmaster", "123456", []];
    };

    const loginSuccessHandler = new Ezy.LoginSuccessHandler();
    loginSuccessHandler.handleLoginSuccess = function () {
        let accessAppRequest = ["hello-ezyfox-server", []];
        this.client.send(Ezy.Command.APP_ACCESS, accessAppRequest);
    };

    const accessAppHandler = new Ezy.AppAccessHandler();
    accessAppHandler.postHandle = function (app: any, data: any) {
      setStatus("App accessed: " + app + ", data: " + data);
    };

    var config = new Ezy.ClientConfig;
    config.zoneName = "hello-ezyfox-server";
    var clients = Ezy.Clients.getInstance();
    var client = clients.newDefaultClient(config);
    let setup = client.setup;
    setup.addDataHandler(Ezy.Command.HANDSHAKE, handshakeHandler);
    setup.addDataHandler(Ezy.Command.LOGIN, loginSuccessHandler);
    setup.addDataHandler(Ezy.Command.APP_ACCESS, accessAppHandler);
    return client;
  }, []);

  return (
    <>
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => websocketClient.connect("ws://localhost:2208/ws")}>
          Connect
        </button>
        <p>
          Status: {status}
        </p>
      </div>
    </>
  )
}

export default App

Lưu ý thư viện ezyfox-es6-client sử dụng javascript thuần thay vì typescript nên bạn sẽ cần tạo ra tập tin ezyfox-es6-client.d.ts trong thư mục src với nội dung như sau:

declare module 'ezyfox-es6-client' {
    const value: any;
    export default value;
}

Khởi chạy chương trình

Quay trở lại với IntelliJ chúng ta sẽ tìm đến tập tin ApplicationStartup nhấn vào nút play để khởi động máy chủ ezyfox server:

Sau đó chúng ta quay trở lại giao diện web và nhấn vào nút connect, kết quả chúng ta nhận được là:

Tổng kết

Như vậy chúng ta đã cùng nhau sử dụng thư viện ezyfox-es6-client để kết nối đến ezyfox-server, trong bài sau chúng ta sẽ cùng tìm hiểu kỹ hơn về ezyfox-server và thư viện ezyfox-es6-client nhé.


Cám ơn bạn đã quan tâm đến bài viết này. Để nhận được thêm các kiến thức bổ ích bạn có thể:

  1. Đọc các bài viết của TechMaster trên facebook: https://www.facebook.com/techmastervn
  2. Xem các video của TechMaster qua Youtube: https://www.youtube.com/@TechMasterVietnam nếu bạn thấy video/bài viết hay bạn có thể theo dõi kênh của TechMaster để nhận được thông báo về các video mới nhất nhé.
  3. Chat với techmaster qua Discord: https://discord.gg/yQjRTFXb7a