服务端异步应答示例

更新时间:
2024-02-20
下载文档

服务端异步应答示例

本章节主要介绍使用中间件开发异步应答功能的方法。

开发示例

本例中 MsgHook 调用 msg_server/warningLampStatus 接口获取警示灯状态然后对当前服务的 /light RPC 执行应答。具体流程如下。

  1. 创建 QVSOA 服务器 light_server
  2. 创建 QVSOA Mware,依次绑定 LogHookMsgHook 两个监听器。
  3. 当客户端 RPC 请求 /light 时,LogHook 将记录 URL 到日志文件并向 MsgHook 传递数据。
  4. MsgHook 打印相应的数据并使用 RPC 请求 msg_server/warningLampStatus 接口同时添加 resolve 作为 RPC 的回调数据。
  5. msg_server 响应 RPC 时,通过 resolve/light 的 RPC 执行应答。
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QProcessEnvironment>
#include <QVsoa>

constexpr char SERVER_INFO[] = "{\"name\":\"light_server\"}";
constexpr char SERVER_PASSWORD[] = "123456";
constexpr char SERVER_ADDR[] = "0.0.0.0";
constexpr int SERVER_PORT = 3001;

class LogHook : public IQVsoaMiddlewareListener
{
public:
    LogHook()
        : m_file(QString("%1/log_file").arg(QDir::tempPath()))
    {
        if (!m_file.open(QIODevice::Append | QIODevice::Text)) {
            exit(-1);
        }
    }

    static void freeLogData(void *data, const QString &)
    {
        free(data);
    }

    bool hook(const QVsoaServer *,
              QPointer<QVsoaCliHandle>,
              const QVsoaHeader &,
              const QString &url,
              const QVsoaPayload &,
              QVsoaMiddlewareResolve &resolve) override
    {
        if (url.length() > 0) {
            auto data = QString("URL: %1\n").arg(url);
            m_file.write(data.toUtf8());
            m_file.flush();

            // Add a new message data to next handler
            resolve.addData("log", strdup("new resolved data"), LogHook::freeLogData);
        }

        // return true to continue processing next hook
        return true;
    }

private:
    QFile m_file;
};

class MsgHook : public QObject,
                public IQVsoaMiddlewareListener
{
    Q_OBJECT
public:
    MsgHook()
        : m_client{},
          m_invoker{&m_client, "/warningLampStatus", RPCMethod::GET}
    {
        connect(&m_client, &QVsoaClient::connected, this, &MsgHook::onConnected);
        connect(&m_invoker, &QVsoaClientRPCInvoker::serverReply, this, &MsgHook::onServerReply);

        m_client.connect2server("vsoa://msg_server", {}, 500);
        m_client.autoConnect(1000, 100);
    }

    bool hook(const QVsoaServer *,
              QPointer<QVsoaCliHandle> client,
              const QVsoaHeader &header,
              const QString &,
              const QVsoaPayload &,
              QVsoaMiddlewareResolve &resolve) override
    {
        // get message data from previous callback
        char *msg = static_cast<char *>(resolve.getData("log"));
        if (msg) {
            qDebug() << QString::asprintf("Log resolved data (key: \"log\") : %s\n", msg);
        }
        m_invoker(QVsoaPayload{}, QVariant::fromValue(resolve));
        return false;
    }

    void onConnected(bool ok, QString info)
    {
        qDebug() << "On connect, connect:" << ok << "info:" << info;
    }

    void onServerReply(const QVsoaHeader header, const QVsoaPayload payload, const QVariant arg)
    {
        auto resolve = arg.value<QVsoaMiddlewareResolve>();
        if (header.isInvalid()) {
            qDebug() << "VSOA server /warningLampStatus reply timeout!";
            return;
        }
        resolve.reply(StatusCode::SUCCESS, header.seqno(), payload);
    }

private:
    QVsoaClient m_client;
    QVsoaClientRPCInvoker m_invoker;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // Initialize server
    QVsoaServer server(SERVER_INFO);
    if (server.isInvalid()) {
        qDebug() << "Can not create VSOA server!";
        return -1;
    }

    // If need password
    server.setPassword(SERVER_PASSWORD);

    LogHook logHook;
    MsgHook msgHook;
    // add mware rpc hook
    // 'logHook' will be called first, if 'logHook' returns 'true'
    // then 'msgHook' will be called
    QVsoaMiddleware mware;
    mware.addListener(&logHook);
    mware.addListener(&msgHook);
    server.addMiddleware("/light", &mware);

    int port = SERVER_PORT;
    int auto_port = QProcessEnvironment::systemEnvironment().value("VSOA_AUTO_PORT", "-1").toInt();
    if (auto_port != -1) {
        port = auto_port;
    }
    // Start server
    if (!server.start(QVsoaSocketAddress(AF_INET, SERVER_ADDR, port))) {
        qDebug() << "Can not start VSOA server!";
        return -1;
    }
    qDebug() << "Started VSOA server.";

    return a.exec();
}

说明
msg_server 可参考RPC 服务端范例开发。

文档内容是否对您有所帮助?
有帮助
没帮助