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; } } } }