[SmartFoxServer] Cách viết một Extension

“SmartFoxServer – Massive multiplayer platform”

SmartFoxServer (SFS) đã thiết kế bản thân nó là một máy chủ chạy ứng dụng, cho nên, công việc của người làm việc đối với SFS chỉ là viết ứng dụng như là một phần mở rộng để gắn vào trong máy chủ đang chạy (giống cơ chế Plugin của các phần mềm hiện tại như Eclipse, Photoshop, …).

Vậy viết một cái Extension như thế nào???

Ở đây, mình sẽ đưa ra một ví dụ về làm một trang Chat (toàn hệ thống), khi một user Login vào hệ thống, thông tin của user sẽ được thông báo đến toàn bộ các user khác, hoặc khi có ai đó gửi bất cứ Message gì, thì Message này đều sẽ được chuyển đến toàn bộ các người chơi khác.

Handlers

Các bạn code SFS bằng Java nên chắc chắn sẽ biết về cơ chế Event Dispatching. SFS cũng vậy, khi có bất cứ request nào từ client, đầu tiên SFS framework sẽ bắt và dựa trên thông tin Event (tên, kiểu) đã đăng ký để gửi đến hàm xử lý của bạn (Handler).

1. Server Handler

Đây là Handler để quản lý các event được “bắn” ra từ SFS (event kiểu này do SFS định sẵn, có vài kiểu thôi, nhưng thông tin đầy đủ). Giới thiệu một số kiểu event như: USER_LOGIN, USER_LOGOUT, ROOM_ADDED, … Các bạn đọc thêm tại: http://docs2x.smartfoxserver.com/api-docs/javadoc/server mục SFSEventType.

Để viết cái này, mình có thể viết một class kế thừa từ BaseServerEventHandler và override lại phương thức handleServerEvent(ISFSEvent isfsEvent) với tham số truyền vào chính là toàn bộ thông tin được chứa trong event này. Tuỳ theo từng loại event mà mình có thể get ra các params phù hợp. Hàm này sẽ được tự động gọi khi có request từ client. (Cẩn thận là không nên implements interface IServerEventHandler thay cho kế thừa BaseServerEventHandler – cái này là trên trang chủ nó thông báo vậy)

Ví dụ ở đây, trong xử lý USER_LOGIN, mình có thể lấy ra đối tượng User chứa thông tin về User vừa login vào hệ thống.

// Example with login event
public void handleServerEvent(ISFSEvent event) throws SFSException {
    if (event.getType().equals(SFSEvent.USER_LOGIN)) {
        User user = event.getParameter(SFSEventParam.USER);
        // do something with user
    }
}
2. Client Handler

Đây là Handler để xử lý cho các event được customs từ client (ở client sẽ gửi lên ExtensionRequest). Khác với SFSEvent do client viết, tuỳ thuộc vào client gửi lên gì mà mình có thể trích xuất từ trong thông tin của event.

Giống với Server Handler, các bạn cũng phải viết 1 class mới, kế thừa BaseClientRequestHandler và override lại phương thức handleClientRequest(User user, ISFSObject params) với user là user đã gửi request và params chứa thông tin client này muốn gửi cho server.

// Example of handle client event
public void handleClientRequest(User user, ISFSObject isfsObject) {
    int direction = isfsObject.getInt("d");
    // do something with direction & user
}
3. Chat Handler

Bây giờ mình sẽ ứng dụng các kiến thức ở trên để viết Handler cho cái đề bài phía trên. Vì đề bài yêu cầu xử lý các event lúc login và gửi message nên mình sẽ phải viết 2 cái handler khác nhau: UserLoginHandler (Server Event) và SendMessageHandler (Client Event).

Class UserLoginHandler.java

public class UserLoginHandler extends BaseServerEventHandler {
    @Override
    public void handleServerEvent(ISFSEvent isfsEvent) throws SFSException {
        User user = (User) isfsEvent.getParameter(SFSEventParam.USER);
        String username = user.getName();
        
        ISFSObject obj = new SFSObject();
        obj.putUtfString("n", username);
        send("new_login", obj, (List<User>) getParentExtension().getParentZone().getUserList()); // notify
    }
}

Class SendMessageHandler.java

public class SendMessageHandler extends BaseClientRequestHandler {
    @Override
    public void handleClientRequest(User user, ISFSObject params) {
        String senderName = user.getName();
        String msgContent = params.getUtfString("c");
        long time = System.currentTimeMillis();
        
        ISFSObject obj = new SFSObject();
        obj.putUtfString("n", senderName);
        obj.putUtfString("c", msgContent);
        obj.putLong("t", time);
        send("new_message", obj, (List<User>) getParentExtension().getParentZone().getUserList()); // notify
    }
}

Một tips nhỏ cho các bạn đó là trong các params giao tiếp giữa client và server: để hạn chế băng thông, “nên” để tên của các params là String với 1 kí tự. Anh kia trong công ty mình đã test thử và bày mình vậy, nghe đâu là tăng tới 70% nếu để tên dài. Ví dụ: “first-name” thì để lại thành “f”.

Trong các ví dụ ở trên sẽ là:

String msgContent = params.getUtfString("c"); // c is represented for content
obj.putUtfString("n", senderName); // n is represented for name

Extension

Khái niệm về Extension khá phức tạp và mình sẽ viết một bài khác để giải thích về nó sau. Trong bài viết này, các bạn cứ hiểu nôm na, Extension là class để mình đăng ký các Handler đã viết ở trên với SFS.

Cụ thể trong đề bài ở trên mình sẽ có một Extension như sau:


public class ChatExtension extends SFSExtension {
    @Override
    public void init() {
        // add event handler
        addEventHandler(SFSEventType.USER_LOGIN, UserLoginHandler.class);

        // add request handler
        addRequestHandler("new_message", SendMessageHandler.class);
    }
}

Xong rồi, giờ chỉ cần build extension ra file jar, deploy vào SFS của bạn và chạy thử. À, nhớ code một đoạn nhỏ client (mình sẽ viết 1 bài hướng dẫn cách viết 1 client bằng java để test và tái sử dụng test các extension khác) để kết nối thử vào server của bạn nhé!

Thân