void TWebSocketWorker::execute(int opcode, const QByteArray &payload)
{
    bool sendTask = false;
    QString es = TUrlRoute::splitPath(_requestPath).value(0).toLower() + "endpoint";
    TDispatcher<TWebSocketEndpoint> dispatcher(es);
    TWebSocketEndpoint *endpoint = dispatcher.object();

    if (!endpoint) {
        return;
    }

    try {
        tSystemDebug("Found endpoint: %s", qPrintable(es));
        tSystemDebug("TWebSocketWorker opcode: %d", opcode);

        endpoint->sessionStore = _socket->session(); // Sets websocket session
        endpoint->uuid = _socket->socketUuid();
        // Database Transaction
        setTransactionEnabled(endpoint->transactionEnabled());

        switch (_mode) {
        case Opening: {
            bool res = endpoint->onOpen(_httpSession);
            if (res) {
                // For switch response
                endpoint->taskList.prepend(qMakePair((int)TWebSocketEndpoint::OpenSuccess, QVariant()));

                if (endpoint->keepAliveInterval() > 0) {
                    endpoint->startKeepAlive(endpoint->keepAliveInterval());
                }
            } else {
                endpoint->taskList.prepend(qMakePair((int)TWebSocketEndpoint::OpenError, QVariant()));
            }
            break; }

        case Closing:
            if (!_socket->closing.exchange(true)) {
                endpoint->onClose(Tf::GoingAway);
                endpoint->unsubscribeFromAll();
            }
            break;

        case Receiving: {

            switch (opcode) {
            case TWebSocketFrame::TextFrame:
                endpoint->onTextReceived(QString::fromUtf8(payload));
                break;

            case TWebSocketFrame::BinaryFrame:
                endpoint->onBinaryReceived(payload);
                break;

            case TWebSocketFrame::Close: {
                quint16 closeCode = Tf::GoingAway;
                if (payload.length() >= 2) {
                    QDataStream ds(payload);
                    ds.setByteOrder(QDataStream::BigEndian);
                    ds >> closeCode;
                }

                if (!_socket->closing.exchange(true)) {
                    endpoint->onClose(closeCode);
                    endpoint->unsubscribeFromAll();
                }
                endpoint->close(closeCode);  // close response or disconnect
                break; }

            case TWebSocketFrame::Ping:
                endpoint->onPing(payload);
                break;

            case TWebSocketFrame::Pong:
                endpoint->onPong(payload);
                break;

            default:
                tSystemWarn("Invalid opcode: 0x%x  [%s:%d]", (int)opcode, __FILE__, __LINE__);
                break;
            }
            break; }

        default:
            break;
        }

        // Sets session to the websocket
        _socket->setSession(endpoint->session());

        for (auto &p : endpoint->taskList) {
            const QVariant &taskData = p.second;

            switch (p.first) {
            case TWebSocketEndpoint::OpenSuccess:
                _socket->sendHandshakeResponse();
                break;

            case TWebSocketEndpoint::OpenError:
                _socket->closing = true;
                _socket->closeSent = true;
                _socket->disconnect();
                goto open_error;
                break;

            case TWebSocketEndpoint::SendText:
                _socket->sendText(taskData.toString());
                sendTask = true;
                break;

            case TWebSocketEndpoint::SendBinary:
                _socket->sendBinary(taskData.toByteArray());
                sendTask = true;
                break;

            case TWebSocketEndpoint::SendClose:
                if (_socket->closing.load() && _socket->closeSent.load()) {
                    // close-frame sent and received
                    _socket->disconnect();
                } else {
                    uint closeCode = taskData.toUInt();
                    _socket->sendClose(closeCode);
                    sendTask = true;
                }
                break;

            case TWebSocketEndpoint::SendPing:
                _socket->sendPing(taskData.toByteArray());
                sendTask = true;
                break;

            case TWebSocketEndpoint::SendPong:
                _socket->sendPong(taskData.toByteArray());
                sendTask = true;
                break;

            case TWebSocketEndpoint::SendTextTo: {
                QVariantList lst = taskData.toList();
                TAbstractWebSocket *websocket = _socket->searchPeerSocket(lst[0].toByteArray());
                if (websocket) {
                    websocket->sendText(lst[1].toString());
                }
                break; }

            case TWebSocketEndpoint::SendBinaryTo: {
                QVariantList lst = taskData.toList();
                TAbstractWebSocket *websocket = _socket->searchPeerSocket(lst[0].toByteArray());
                if (websocket) {
                    websocket->sendBinary(lst[1].toByteArray());
                }
                break; }

            case TWebSocketEndpoint::SendCloseTo: {
                QVariantList lst = taskData.toList();
                TAbstractWebSocket *websocket = _socket->searchPeerSocket(lst[0].toByteArray());
                if (websocket) {
                    websocket->sendClose(lst[1].toInt());
                }
                break; }

            case TWebSocketEndpoint::Subscribe: {
                QVariantList lst = taskData.toList();
                TPublisher::instance()->subscribe(lst[0].toString(), lst[1].toBool(), _socket);
                break; }

            case TWebSocketEndpoint::Unsubscribe:
                TPublisher::instance()->unsubscribe(taskData.toString(), _socket);
                break;

            case TWebSocketEndpoint::UnsubscribeFromAll:
                TPublisher::instance()->unsubscribeFromAll(_socket);
                break;

            case TWebSocketEndpoint::PublishText: {
                QVariantList lst = taskData.toList();
                TPublisher::instance()->publish(lst[0].toString(), lst[1].toString(), _socket);
                break; }

            case TWebSocketEndpoint::PublishBinary: {
                QVariantList lst = taskData.toList();
                TPublisher::instance()->publish(lst[0].toString(), lst[1].toByteArray(), _socket);
                break; }

            case TWebSocketEndpoint::StartKeepAlive:
                _socket->startKeepAlive(taskData.toInt());
                break;

            case TWebSocketEndpoint::StopKeepAlive:
                _socket->stopKeepAlive();
                break;

            default:
                tSystemError("Invalid logic  [%s:%d]",  __FILE__, __LINE__);
                break;
            }
        }

        if (!sendTask) {
            // Receiving but not sending, so renew keep-alive
            _socket->renewKeepAlive();
        }

    open_error:
        // transaction
        if (Q_UNLIKELY(endpoint->rollbackRequested())) {
            rollbackTransactions();
        } else {
            // Commits a transaction to the database
            commitTransactions();
        }

    } catch (ClientErrorException &e) {
void TWebSocketWorker::run()
{
    QString es = TUrlRoute::splitPath(requestPath).value(0).toLower() + "endpoint";
    TDispatcher<TWebSocketEndpoint> dispatcher(es);
    TWebSocketEndpoint *endpoint = dispatcher.object();

    if (endpoint) {
        tSystemDebug("Found endpoint: %s", qPrintable(es));
        tSystemDebug("TWebSocketWorker opcode: %d", opcode);

        switch (opcode) {
        case TWebSocketFrame::Continuation:   // means session opening
            if (sessionStore.id().isEmpty()) {
                endpoint->onOpen(sessionStore);
            } else {
                tError("Invalid logic  [%s:%d]",  __FILE__, __LINE__);
            }
            break;

        case TWebSocketFrame::TextFrame:
            endpoint->onTextReceived(QString::fromUtf8(requestData));
            break;

        case TWebSocketFrame::BinaryFrame:
            endpoint->onBinaryReceived(requestData);
            break;

        case TWebSocketFrame::Close:
            endpoint->onClose();
            endpoint->closeWebSocket();
            break;

        case TWebSocketFrame::Ping:
            endpoint->onPing();
            endpoint->sendPong();
            break;

        case TWebSocketFrame::Pong:
            endpoint->onPong();
            break;

        default:
            tWarn("Invalid opcode: 0x%x  [%s:%d]", (int)opcode, __FILE__, __LINE__);
            break;
        }

        // Sends payload
        for (QListIterator<QVariant> it(endpoint->payloadList); it.hasNext(); ) {
            const QVariant &var = it.next();
            switch (var.type()) {
            case QVariant::String:
                socket->sendText(var.toString());
                break;

            case QVariant::ByteArray:
                socket->sendBinary(var.toByteArray());
                break;

            case QVariant::Int: {

                int opcode = var.toInt();
                switch (opcode) {
                case TWebSocketFrame::Close:
                    socket->disconnect();
                    break;

                case TWebSocketFrame::Ping:
                    socket->sendPing();
                    break;

                case TWebSocketFrame::Pong:
                    socket->sendPong();
                    break;

                default:
                    tError("Invalid logic  [%s:%d]",  __FILE__, __LINE__);
                    break;
                }

                break; }

            default:
                tError("Invalid logic  [%s:%d]",  __FILE__, __LINE__);
                break;
            }
        }
    }
}