From 10910aa06ddb2d872ce8274eda72aabab5cf4cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Tue, 2 Feb 2021 11:26:22 +0100 Subject: [PATCH] requests(general): ExecuteBatch WIP --- src/WSRequestHandler.cpp | 4 +- src/WSRequestHandler.h | 2 + src/WSRequestHandler_General.cpp | 45 +++++++++++++++++++ src/WSServer.cpp | 6 +-- src/protocol/OBSRemoteProtocol.cpp | 69 +++++++++++++++++++----------- src/protocol/OBSRemoteProtocol.h | 15 ++++--- src/rpc/RpcResponse.h | 2 +- 7 files changed, 105 insertions(+), 38 deletions(-) diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 5c502727..67036179 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -46,6 +46,8 @@ const QHash WSRequestHandler::messageMap{ { "TriggerHotkeyByName", &WSRequestHandler::TriggerHotkeyByName }, { "TriggerHotkeyBySequence", &WSRequestHandler::TriggerHotkeyBySequence }, + { "ExecuteBatch", &WSRequestHandler::ExecuteBatch }, + { "SetCurrentScene", &WSRequestHandler::SetCurrentScene }, { "GetCurrentScene", &WSRequestHandler::GetCurrentScene }, { "GetSceneList", &WSRequestHandler::GetSceneList }, @@ -189,7 +191,7 @@ WSRequestHandler::WSRequestHandler(ConnectionProperties& connProperties) : { } -RpcResponse WSRequestHandler::processRequest(const RpcRequest& request){ +RpcResponse WSRequestHandler::processRequest(const RpcRequest& request) { if (GetConfig()->AuthRequired && (!authNotRequired.contains(request.methodName())) && (!_connProperties.isAuthenticated())) diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index 16a64742..6ac744a4 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -64,6 +64,8 @@ class WSRequestHandler { RpcResponse TriggerHotkeyByName(const RpcRequest&); RpcResponse TriggerHotkeyBySequence(const RpcRequest&); + RpcResponse ExecuteBatch(const RpcRequest&); + RpcResponse SetCurrentScene(const RpcRequest&); RpcResponse GetCurrentScene(const RpcRequest&); RpcResponse GetSceneList(const RpcRequest&); diff --git a/src/WSRequestHandler_General.cpp b/src/WSRequestHandler_General.cpp index d42513bc..fdef74e4 100644 --- a/src/WSRequestHandler_General.cpp +++ b/src/WSRequestHandler_General.cpp @@ -7,6 +7,7 @@ #include "Config.h" #include "Utils.h" #include "WSEvents.h" +#include "protocol/OBSRemoteProtocol.h" #define CASE(x) case x: return #x; const char *describe_output_format(int format) { @@ -415,3 +416,47 @@ RpcResponse WSRequestHandler::TriggerHotkeyBySequence(const RpcRequest& request) return request.success(); } + +/** +* Executes a list of requests sequentially. +* +* @param {Array} `requests` +* +* @return {Array} `results` +* +* @api requests +* @name ExecuteBatch +* @category general +* @since unreleased +*/ +RpcResponse WSRequestHandler::ExecuteBatch(const RpcRequest& request) { + if (!request.hasField("requests")) { + return request.failed("missing request parameters"); + } + + OBSDataArrayAutoRelease results = obs_data_array_create(); + + OBSDataArrayAutoRelease requests = obs_data_get_array(request.parameters(), "requests"); + size_t requestsCount = obs_data_array_count(requests); + for (size_t i = 0; i < requestsCount; i++) { + OBSDataAutoRelease requestData = obs_data_array_item(requests, i); + QString methodName = obs_data_get_string(requestData, "request-type"); + obs_data_unset_user_value(requestData, "request-type"); + obs_data_unset_user_value(requestData, "message-id"); + + // build RpcRequest from json data object + RpcRequest subRequest(QString::Null(), methodName, requestData); + + // execute the request + RpcResponse subResponse = processRequest(subRequest); + + // transform response into json data + OBSDataAutoRelease subResponseData = OBSRemoteProtocol::rpcResponseToJsonData(subResponse); + + obs_data_array_push_back(results, subResponseData); + } + + OBSDataAutoRelease response = obs_data_create(); + obs_data_set_array(response, "results", results); + return request.success(response); +} diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 6d155658..8f1ec8bf 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -133,8 +133,7 @@ void WSServer::stop() void WSServer::broadcast(const RpcEvent& event) { - OBSRemoteProtocol protocol; - std::string message = protocol.encodeEvent(event); + std::string message = OBSRemoteProtocol::encodeEvent(event); if (GetConfig()->DebugEnabled) { blog(LOG_INFO, "Update << '%s'", message.c_str()); @@ -190,8 +189,7 @@ void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) } WSRequestHandler requestHandler(connProperties); - OBSRemoteProtocol protocol; - std::string response = protocol.processMessage(requestHandler, payload); + std::string response = OBSRemoteProtocol::processMessage(requestHandler, payload); if (GetConfig()->DebugEnabled) { blog(LOG_INFO, "Response << '%s'", response.c_str()); diff --git a/src/protocol/OBSRemoteProtocol.cpp b/src/protocol/OBSRemoteProtocol.cpp index a7555b6e..e02be58d 100644 --- a/src/protocol/OBSRemoteProtocol.cpp +++ b/src/protocol/OBSRemoteProtocol.cpp @@ -31,11 +31,15 @@ std::string OBSRemoteProtocol::processMessage(WSRequestHandler& requestHandler, OBSDataAutoRelease data = obs_data_create_from_json(msg); if (!data) { blog(LOG_ERROR, "invalid JSON payload received for '%s'", msg); - return errorResponse(QString::Null(), "invalid JSON payload"); + return jsonDataToString( + errorResponse(nullptr, "invalid JSON payload") + ); } if (!obs_data_has_user_value(data, "request-type") || !obs_data_has_user_value(data, "message-id")) { - return errorResponse(QString::Null(), "missing request parameters"); + return jsonDataToString( + errorResponse(nullptr, "missing request parameters") + ); } QString methodName = obs_data_get_string(data, "request-type"); @@ -49,15 +53,8 @@ std::string OBSRemoteProtocol::processMessage(WSRequestHandler& requestHandler, RpcRequest request(messageId, methodName, params); RpcResponse response = requestHandler.processRequest(request); - OBSData additionalFields = response.additionalFields(); - switch (response.status()) { - case RpcResponse::Status::Ok: - return successResponse(messageId, additionalFields); - case RpcResponse::Status::Error: - return errorResponse(messageId, response.errorMessage(), additionalFields); - } - - return std::string(); + OBSData responseData = rpcResponseToJsonData(response); + return jsonDataToString(responseData); } std::string OBSRemoteProtocol::encodeEvent(const RpcEvent& event) @@ -87,33 +84,53 @@ std::string OBSRemoteProtocol::encodeEvent(const RpcEvent& event) return std::string(obs_data_get_json(eventData)); } -std::string OBSRemoteProtocol::buildResponse(QString messageId, QString status, obs_data_t* fields) +obs_data_t* OBSRemoteProtocol::rpcResponseToJsonData(const RpcResponse& response) { - OBSDataAutoRelease response = obs_data_create(); - if (!messageId.isNull()) { - obs_data_set_string(response, "message-id", messageId.toUtf8().constData()); + const char* messageId = response.messageId().toUtf8().constData(); + OBSData additionalFields = response.additionalFields(); + switch (response.status()) { + case RpcResponse::Status::Ok: + return successResponse(messageId, additionalFields); + case RpcResponse::Status::Error: + return errorResponse(messageId, response.errorMessage().toUtf8().constData(), additionalFields); + default: + assert(false); } - obs_data_set_string(response, "status", status.toUtf8().constData()); - - if (fields) { - obs_data_apply(response, fields); - } - - std::string responseString = obs_data_get_json(response); - return responseString; } -std::string OBSRemoteProtocol::successResponse(QString messageId, obs_data_t* fields) +obs_data_t* OBSRemoteProtocol::successResponse(const char* messageId, obs_data_t* fields) { return buildResponse(messageId, "ok", fields); } -std::string OBSRemoteProtocol::errorResponse(QString messageId, QString errorMessage, obs_data_t* additionalFields) +obs_data_t* OBSRemoteProtocol::errorResponse(const char* messageId, const char* errorMessage, obs_data_t* additionalFields) { OBSDataAutoRelease fields = obs_data_create(); if (additionalFields) { obs_data_apply(fields, additionalFields); } - obs_data_set_string(fields, "error", errorMessage.toUtf8().constData()); + obs_data_set_string(fields, "error", errorMessage); return buildResponse(messageId, "error", fields); } + +obs_data_t* OBSRemoteProtocol::buildResponse(const char* messageId, const char* status, obs_data_t* fields) +{ + OBSDataAutoRelease response = obs_data_create(); + if (messageId) { + obs_data_set_string(response, "message-id", messageId); + } + obs_data_set_string(response, "status", status); + + if (fields) { + obs_data_apply(response, fields); + } + + obs_data_addref(response); + return response; +} + +std::string OBSRemoteProtocol::jsonDataToString(obs_data_t* data) +{ + std::string responseString = obs_data_get_json(data); + return responseString; +} diff --git a/src/protocol/OBSRemoteProtocol.h b/src/protocol/OBSRemoteProtocol.h index 03d8aa7d..f518a002 100644 --- a/src/protocol/OBSRemoteProtocol.h +++ b/src/protocol/OBSRemoteProtocol.h @@ -20,7 +20,8 @@ with this program. If not, see #include #include -#include + +#include "../rpc/RpcResponse.h" class WSRequestHandler; class RpcEvent; @@ -28,11 +29,13 @@ class RpcEvent; class OBSRemoteProtocol { public: - std::string processMessage(WSRequestHandler& requestHandler, std::string message); - std::string encodeEvent(const RpcEvent& event); + static std::string processMessage(WSRequestHandler& requestHandler, std::string message); + static std::string encodeEvent(const RpcEvent& event); + static obs_data_t* rpcResponseToJsonData(const RpcResponse& response); private: - std::string buildResponse(QString messageId, QString status, obs_data_t* fields = nullptr); - std::string successResponse(QString messageId, obs_data_t* fields = nullptr); - std::string errorResponse(QString messageId, QString errorMessage, obs_data_t* additionalFields = nullptr); + static obs_data_t* successResponse(const char* messageId, obs_data_t* fields = nullptr); + static obs_data_t* errorResponse(const char* messageId, const char* errorMessage, obs_data_t* additionalFields = nullptr); + static obs_data_t* buildResponse(const char* messageId, const char*, obs_data_t* fields = nullptr); + static std::string jsonDataToString(obs_data_t* data); }; diff --git a/src/rpc/RpcResponse.h b/src/rpc/RpcResponse.h index a6381bfd..d0c96d6e 100644 --- a/src/rpc/RpcResponse.h +++ b/src/rpc/RpcResponse.h @@ -36,7 +36,7 @@ public: obs_data_t* additionalFields = nullptr ); - Status status() { + const Status status() const { return _status; }