diff --git a/CMakeLists.txt b/CMakeLists.txt index 435a4e37..520d4254 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,10 @@ set(obs-websocket_SOURCES src/WSEvents.cpp src/Config.cpp src/Utils.cpp + src/rpc/RpcRequest.cpp + src/rpc/RpcResponse.cpp + src/rpc/RpcEvent.cpp + src/protocol/OBSRemoteProtocol.cpp src/forms/settings-dialog.cpp) set(obs-websocket_HEADERS @@ -56,6 +60,10 @@ set(obs-websocket_HEADERS src/WSEvents.h src/Config.h src/Utils.h + src/rpc/RpcRequest.h + src/rpc/RpcResponse.h + src/rpc/RpcEvent.h + src/protocol/OBSRemoteProtocol.h src/forms/settings-dialog.h) # --- Platform-independent build settings --- @@ -174,8 +182,8 @@ if(UNIX AND NOT APPLE) install(TARGETS obs-websocket LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/obs-plugins") # Dirty fix for Ubuntu - install(TARGETS obs-websocket - LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/${UNAME_MACHINE}-linux-gnu/obs-plugins") + install(TARGETS obs-websocket + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/${UNAME_MACHINE}-linux-gnu/obs-plugins") install(FILES ${locale_files} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/obs-websocket/locale") diff --git a/src/Utils.cpp b/src/Utils.cpp index b1b08d5c..cb381d0f 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ +#include #include #include #include @@ -822,3 +823,17 @@ void Utils::PauseRecording(bool pause) pauseRecording(pause); } + +QString Utils::nsToTimestamp(uint64_t ns) +{ + uint64_t ms = ns / 1000000ULL; + uint64_t secs = ms / 1000ULL; + uint64_t minutes = secs / 60ULL; + + uint64_t hoursPart = minutes / 60ULL; + uint64_t minutesPart = minutes % 60ULL; + uint64_t secsPart = secs % 60ULL; + uint64_t msPart = ms % 1000ULL; + + return QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); +} diff --git a/src/Utils.h b/src/Utils.h index 89f01acc..bdd5da20 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -86,4 +86,6 @@ class Utils { static bool RecordingPauseSupported(); static bool RecordingPaused(); static void PauseRecording(bool pause); + + static QString nsToTimestamp(uint64_t ns); }; diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index d7d04055..4c48e683 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -23,27 +23,15 @@ #include -#include "Config.h" -#include "Utils.h" #include "WSEvents.h" #include "obs-websocket.h" +#include "Config.h" +#include "Utils.h" +#include "rpc/RpcEvent.h" #define STATUS_INTERVAL 2000 -QString nsToTimestamp(uint64_t ns) { - uint64_t ms = ns / 1000000ULL; - uint64_t secs = ms / 1000ULL; - uint64_t minutes = secs / 60ULL; - - uint64_t hoursPart = minutes / 60ULL; - uint64_t minutesPart = minutes % 60ULL; - uint64_t secsPart = secs % 60ULL; - uint64_t msPart = ms % 1000ULL; - - return QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); -} - const char* sourceTypeToString(obs_source_type type) { switch (type) { case OBS_SOURCE_TYPE_INPUT: @@ -252,28 +240,11 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private void WSEvents::broadcastUpdate(const char* updateType, obs_data_t* additionalFields = nullptr) { - OBSDataAutoRelease update = obs_data_create(); - obs_data_set_string(update, "update-type", updateType); + uint64_t streamTime = getStreamingTime(); + uint64_t recordingTime = getStreamingTime(); + RpcEvent event(QString(updateType), streamTime, recordingTime, additionalFields); - if (obs_frontend_streaming_active()) { - QString streamingTimecode = getStreamingTimecode(); - obs_data_set_string(update, "stream-timecode", streamingTimecode.toUtf8().constData()); - } - - if (obs_frontend_recording_active()) { - QString recordingTimecode = getRecordingTimecode(); - obs_data_set_string(update, "rec-timecode", recordingTimecode.toUtf8().constData()); - } - - if (additionalFields) - obs_data_apply(update, additionalFields); - - QString json = obs_data_get_json(update); - _srv->broadcast(json.toStdString()); - - if (GetConfig()->DebugEnabled) { - blog(LOG_INFO, "Update << '%s'", json.toUtf8().constData()); - } + _srv->broadcast(event); } void WSEvents::connectSourceSignals(obs_source_t* source) { @@ -410,11 +381,11 @@ uint64_t WSEvents::getRecordingTime() { } QString WSEvents::getStreamingTimecode() { - return nsToTimestamp(getStreamingTime()); + return Utils::nsToTimestamp(getStreamingTime()); } QString WSEvents::getRecordingTimecode() { - return nsToTimestamp(getRecordingTime()); + return Utils::nsToTimestamp(getRecordingTime()); } /** diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 8b31c0b7..0f10fad6 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -17,6 +17,8 @@ * with this program. If not, see */ +#include + #include #include "Config.h" @@ -24,265 +26,148 @@ #include "WSRequestHandler.h" -QHash WSRequestHandler::messageMap{ - { "GetVersion", WSRequestHandler::HandleGetVersion }, - { "GetAuthRequired", WSRequestHandler::HandleGetAuthRequired }, - { "Authenticate", WSRequestHandler::HandleAuthenticate }, +using namespace std::placeholders; - { "GetStats", WSRequestHandler::HandleGetStats }, - { "SetHeartbeat", WSRequestHandler::HandleSetHeartbeat }, - { "GetVideoInfo", WSRequestHandler::HandleGetVideoInfo }, +const QHash WSRequestHandler::messageMap { + { "GetVersion", &WSRequestHandler::GetVersion }, + { "GetAuthRequired", &WSRequestHandler::GetAuthRequired }, + { "Authenticate", &WSRequestHandler::Authenticate }, - { "SetFilenameFormatting", WSRequestHandler::HandleSetFilenameFormatting }, - { "GetFilenameFormatting", WSRequestHandler::HandleGetFilenameFormatting }, + { "GetStats", &WSRequestHandler::GetStats }, + { "SetHeartbeat", &WSRequestHandler::SetHeartbeat }, + { "GetVideoInfo", &WSRequestHandler::GetVideoInfo }, - { "BroadcastCustomMessage", WSRequestHandler::HandleBroadcastCustomMessage }, + { "SetFilenameFormatting", &WSRequestHandler::SetFilenameFormatting }, + { "GetFilenameFormatting", &WSRequestHandler::GetFilenameFormatting }, - { "SetCurrentScene", WSRequestHandler::HandleSetCurrentScene }, - { "GetCurrentScene", WSRequestHandler::HandleGetCurrentScene }, - { "GetSceneList", WSRequestHandler::HandleGetSceneList }, + { "BroadcastCustomMessage", &WSRequestHandler::BroadcastCustomMessage }, - { "SetSourceRender", WSRequestHandler::HandleSetSceneItemRender }, // Retrocompat - { "SetSceneItemRender", WSRequestHandler::HandleSetSceneItemRender }, - { "SetSceneItemPosition", WSRequestHandler::HandleSetSceneItemPosition }, - { "SetSceneItemTransform", WSRequestHandler::HandleSetSceneItemTransform }, - { "SetSceneItemCrop", WSRequestHandler::HandleSetSceneItemCrop }, - { "GetSceneItemProperties", WSRequestHandler::HandleGetSceneItemProperties }, - { "SetSceneItemProperties", WSRequestHandler::HandleSetSceneItemProperties }, - { "ResetSceneItem", WSRequestHandler::HandleResetSceneItem }, - { "DeleteSceneItem", WSRequestHandler::HandleDeleteSceneItem }, - { "DuplicateSceneItem", WSRequestHandler::HandleDuplicateSceneItem }, - { "ReorderSceneItems", WSRequestHandler::HandleReorderSceneItems }, + { "SetCurrentScene", &WSRequestHandler::SetCurrentScene }, + { "GetCurrentScene", &WSRequestHandler::GetCurrentScene }, + { "GetSceneList", &WSRequestHandler::GetSceneList }, - { "GetStreamingStatus", WSRequestHandler::HandleGetStreamingStatus }, - { "StartStopStreaming", WSRequestHandler::HandleStartStopStreaming }, - { "StartStopRecording", WSRequestHandler::HandleStartStopRecording }, + { "SetSourceRender", &WSRequestHandler::SetSceneItemRender }, // Retrocompat + { "SetSceneItemRender", &WSRequestHandler::SetSceneItemRender }, + { "SetSceneItemPosition", &WSRequestHandler::SetSceneItemPosition }, + { "SetSceneItemTransform", &WSRequestHandler::SetSceneItemTransform }, + { "SetSceneItemCrop", &WSRequestHandler::SetSceneItemCrop }, + { "GetSceneItemProperties", &WSRequestHandler::GetSceneItemProperties }, + { "SetSceneItemProperties", &WSRequestHandler::SetSceneItemProperties }, + { "ResetSceneItem", &WSRequestHandler::ResetSceneItem }, + { "DeleteSceneItem", &WSRequestHandler::DeleteSceneItem }, + { "DuplicateSceneItem", &WSRequestHandler::DuplicateSceneItem }, + { "ReorderSceneItems", &WSRequestHandler::ReorderSceneItems }, - { "StartStreaming", WSRequestHandler::HandleStartStreaming }, - { "StopStreaming", WSRequestHandler::HandleStopStreaming }, + { "GetStreamingStatus", &WSRequestHandler::GetStreamingStatus }, + { "StartStopStreaming", &WSRequestHandler::StartStopStreaming }, + { "StartStopRecording", &WSRequestHandler::StartStopRecording }, - { "StartRecording", WSRequestHandler::HandleStartRecording }, - { "StopRecording", WSRequestHandler::HandleStopRecording }, - { "PauseRecording", WSRequestHandler::HandlePauseRecording }, - { "ResumeRecording", WSRequestHandler::HandleResumeRecording }, + { "StartStreaming", &WSRequestHandler::StartStreaming }, + { "StopStreaming", &WSRequestHandler::StopStreaming }, - { "StartStopReplayBuffer", WSRequestHandler::HandleStartStopReplayBuffer }, - { "StartReplayBuffer", WSRequestHandler::HandleStartReplayBuffer }, - { "StopReplayBuffer", WSRequestHandler::HandleStopReplayBuffer }, - { "SaveReplayBuffer", WSRequestHandler::HandleSaveReplayBuffer }, + { "StartRecording", &WSRequestHandler::StartRecording }, + { "StopRecording", &WSRequestHandler::StopRecording }, + { "PauseRecording", &WSRequestHandler::PauseRecording }, + { "ResumeRecording", &WSRequestHandler::ResumeRecording }, - { "SetRecordingFolder", WSRequestHandler::HandleSetRecordingFolder }, - { "GetRecordingFolder", WSRequestHandler::HandleGetRecordingFolder }, + { "StartStopReplayBuffer", &WSRequestHandler::StartStopReplayBuffer }, + { "StartReplayBuffer", &WSRequestHandler::StartReplayBuffer }, + { "StopReplayBuffer", &WSRequestHandler::StopReplayBuffer }, + { "SaveReplayBuffer", &WSRequestHandler::SaveReplayBuffer }, - { "GetTransitionList", WSRequestHandler::HandleGetTransitionList }, - { "GetCurrentTransition", WSRequestHandler::HandleGetCurrentTransition }, - { "SetCurrentTransition", WSRequestHandler::HandleSetCurrentTransition }, - { "SetTransitionDuration", WSRequestHandler::HandleSetTransitionDuration }, - { "GetTransitionDuration", WSRequestHandler::HandleGetTransitionDuration }, + { "SetRecordingFolder", &WSRequestHandler::SetRecordingFolder }, + { "GetRecordingFolder", &WSRequestHandler::GetRecordingFolder }, - { "SetVolume", WSRequestHandler::HandleSetVolume }, - { "GetVolume", WSRequestHandler::HandleGetVolume }, - { "ToggleMute", WSRequestHandler::HandleToggleMute }, - { "SetMute", WSRequestHandler::HandleSetMute }, - { "GetMute", WSRequestHandler::HandleGetMute }, - { "SetSyncOffset", WSRequestHandler::HandleSetSyncOffset }, - { "GetSyncOffset", WSRequestHandler::HandleGetSyncOffset }, - { "GetSpecialSources", WSRequestHandler::HandleGetSpecialSources }, - { "GetSourcesList", WSRequestHandler::HandleGetSourcesList }, - { "GetSourceTypesList", WSRequestHandler::HandleGetSourceTypesList }, - { "GetSourceSettings", WSRequestHandler::HandleGetSourceSettings }, - { "SetSourceSettings", WSRequestHandler::HandleSetSourceSettings }, - { "TakeSourceScreenshot", WSRequestHandler::HandleTakeSourceScreenshot }, + { "GetTransitionList", &WSRequestHandler::GetTransitionList }, + { "GetCurrentTransition", &WSRequestHandler::GetCurrentTransition }, + { "SetCurrentTransition", &WSRequestHandler::SetCurrentTransition }, + { "SetTransitionDuration", &WSRequestHandler::SetTransitionDuration }, + { "GetTransitionDuration", &WSRequestHandler::GetTransitionDuration }, - { "GetSourceFilters", WSRequestHandler::HandleGetSourceFilters }, - { "GetSourceFilterInfo", WSRequestHandler::HandleGetSourceFilterInfo }, - { "AddFilterToSource", WSRequestHandler::HandleAddFilterToSource }, - { "RemoveFilterFromSource", WSRequestHandler::HandleRemoveFilterFromSource }, - { "ReorderSourceFilter", WSRequestHandler::HandleReorderSourceFilter }, - { "MoveSourceFilter", WSRequestHandler::HandleMoveSourceFilter }, - { "SetSourceFilterSettings", WSRequestHandler::HandleSetSourceFilterSettings }, - { "SetSourceFilterVisibility", WSRequestHandler::HandleSetSourceFilterVisibility }, + { "SetVolume", &WSRequestHandler::SetVolume }, + { "GetVolume", &WSRequestHandler::GetVolume }, + { "ToggleMute", &WSRequestHandler::ToggleMute }, + { "SetMute", &WSRequestHandler::SetMute }, + { "GetMute", &WSRequestHandler::GetMute }, + { "SetSyncOffset", &WSRequestHandler::SetSyncOffset }, + { "GetSyncOffset", &WSRequestHandler::GetSyncOffset }, + { "GetSpecialSources", &WSRequestHandler::GetSpecialSources }, + { "GetSourcesList", &WSRequestHandler::GetSourcesList }, + { "GetSourceTypesList", &WSRequestHandler::GetSourceTypesList }, + { "GetSourceSettings", &WSRequestHandler::GetSourceSettings }, + { "SetSourceSettings", &WSRequestHandler::SetSourceSettings }, + { "TakeSourceScreenshot", &WSRequestHandler::TakeSourceScreenshot }, - { "SetCurrentSceneCollection", WSRequestHandler::HandleSetCurrentSceneCollection }, - { "GetCurrentSceneCollection", WSRequestHandler::HandleGetCurrentSceneCollection }, - { "ListSceneCollections", WSRequestHandler::HandleListSceneCollections }, + { "GetSourceFilters", &WSRequestHandler::GetSourceFilters }, + { "GetSourceFilterInfo", &WSRequestHandler::GetSourceFilterInfo }, + { "AddFilterToSource", &WSRequestHandler::AddFilterToSource }, + { "RemoveFilterFromSource", &WSRequestHandler::RemoveFilterFromSource }, + { "ReorderSourceFilter", &WSRequestHandler::ReorderSourceFilter }, + { "MoveSourceFilter", &WSRequestHandler::MoveSourceFilter }, + { "SetSourceFilterSettings", &WSRequestHandler::SetSourceFilterSettings }, + { "SetSourceFilterVisibility", &WSRequestHandler::SetSourceFilterVisibility }, - { "SetCurrentProfile", WSRequestHandler::HandleSetCurrentProfile }, - { "GetCurrentProfile", WSRequestHandler::HandleGetCurrentProfile }, - { "ListProfiles", WSRequestHandler::HandleListProfiles }, + { "SetCurrentSceneCollection", &WSRequestHandler::SetCurrentSceneCollection }, + { "GetCurrentSceneCollection", &WSRequestHandler::GetCurrentSceneCollection }, + { "ListSceneCollections", &WSRequestHandler::ListSceneCollections }, - { "SetStreamSettings", WSRequestHandler::HandleSetStreamSettings }, - { "GetStreamSettings", WSRequestHandler::HandleGetStreamSettings }, - { "SaveStreamSettings", WSRequestHandler::HandleSaveStreamSettings }, + { "SetCurrentProfile", &WSRequestHandler::SetCurrentProfile }, + { "GetCurrentProfile", &WSRequestHandler::GetCurrentProfile }, + { "ListProfiles", &WSRequestHandler::ListProfiles }, + + { "SetStreamSettings", &WSRequestHandler::SetStreamSettings }, + { "GetStreamSettings", &WSRequestHandler::GetStreamSettings }, + { "SaveStreamSettings", &WSRequestHandler::SaveStreamSettings }, #if BUILD_CAPTIONS - { "SendCaptions", WSRequestHandler::HandleSendCaptions }, + { "SendCaptions", &WSRequestHandler::SendCaptions }, #endif - { "GetStudioModeStatus", WSRequestHandler::HandleGetStudioModeStatus }, - { "GetPreviewScene", WSRequestHandler::HandleGetPreviewScene }, - { "SetPreviewScene", WSRequestHandler::HandleSetPreviewScene }, - { "TransitionToProgram", WSRequestHandler::HandleTransitionToProgram }, - { "EnableStudioMode", WSRequestHandler::HandleEnableStudioMode }, - { "DisableStudioMode", WSRequestHandler::HandleDisableStudioMode }, - { "ToggleStudioMode", WSRequestHandler::HandleToggleStudioMode }, + { "GetStudioModeStatus", &WSRequestHandler::GetStudioModeStatus }, + { "GetPreviewScene", &WSRequestHandler::GetPreviewScene }, + { "SetPreviewScene", &WSRequestHandler::SetPreviewScene }, + { "TransitionToProgram", &WSRequestHandler::TransitionToProgram }, + { "EnableStudioMode", &WSRequestHandler::EnableStudioMode }, + { "DisableStudioMode", &WSRequestHandler::DisableStudioMode }, + { "ToggleStudioMode", &WSRequestHandler::ToggleStudioMode }, - { "SetTextGDIPlusProperties", WSRequestHandler::HandleSetTextGDIPlusProperties }, - { "GetTextGDIPlusProperties", WSRequestHandler::HandleGetTextGDIPlusProperties }, + { "SetTextGDIPlusProperties", &WSRequestHandler::SetTextGDIPlusProperties }, + { "GetTextGDIPlusProperties", &WSRequestHandler::GetTextGDIPlusProperties }, - { "SetTextFreetype2Properties", WSRequestHandler::HandleSetTextFreetype2Properties }, - { "GetTextFreetype2Properties", WSRequestHandler::HandleGetTextFreetype2Properties }, + { "SetTextFreetype2Properties", &WSRequestHandler::SetTextFreetype2Properties }, + { "GetTextFreetype2Properties", &WSRequestHandler::GetTextFreetype2Properties }, - { "GetBrowserSourceProperties", WSRequestHandler::HandleGetBrowserSourceProperties }, - { "SetBrowserSourceProperties", WSRequestHandler::HandleSetBrowserSourceProperties }, + { "GetBrowserSourceProperties", &WSRequestHandler::GetBrowserSourceProperties }, + { "SetBrowserSourceProperties", &WSRequestHandler::SetBrowserSourceProperties }, - { "ListOutputs", WSRequestHandler::HandleListOutputs }, - { "GetOutputInfo", WSRequestHandler::HandleGetOutputInfo }, - { "StartOutput", WSRequestHandler::HandleStartOutput }, - { "StopOutput", WSRequestHandler::HandleStopOutput } + { "ListOutputs", &WSRequestHandler::ListOutputs }, + { "GetOutputInfo", &WSRequestHandler::GetOutputInfo }, + { "StartOutput", &WSRequestHandler::StartOutput }, + { "StopOutput", &WSRequestHandler::StopOutput } }; -QSet WSRequestHandler::authNotRequired { +const QSet WSRequestHandler::authNotRequired { "GetVersion", "GetAuthRequired", "Authenticate" }; WSRequestHandler::WSRequestHandler(ConnectionProperties& connProperties) : - _messageId(0), - _requestType(""), - data(nullptr), _connProperties(connProperties) { } -std::string WSRequestHandler::processIncomingMessage(std::string& textMessage) { - if (GetConfig()->DebugEnabled) { - blog(LOG_INFO, "Request >> '%s'", textMessage.c_str()); - } - - OBSDataAutoRelease responseData = processRequest(textMessage); - std::string response = obs_data_get_json(responseData); - - if (GetConfig()->DebugEnabled) { - blog(LOG_INFO, "Response << '%s'", response.c_str()); - } - - return response; -} - -HandlerResponse WSRequestHandler::processRequest(std::string& textMessage){ - std::string msgContainer(textMessage); - const char* msg = msgContainer.c_str(); - - data = obs_data_create_from_json(msg); - if (!data) { - blog(LOG_ERROR, "invalid JSON payload received for '%s'", msg); - return SendErrorResponse("invalid JSON payload"); - } - - if (!hasField("request-type") || !hasField("message-id")) { - return SendErrorResponse("missing request parameters"); - } - - _requestType = obs_data_get_string(data, "request-type"); - _messageId = obs_data_get_string(data, "message-id"); - +RpcResponse WSRequestHandler::processRequest(const RpcRequest& request){ if (GetConfig()->AuthRequired - && (!authNotRequired.contains(_requestType)) + && (!authNotRequired.contains(request.methodName())) && (!_connProperties.isAuthenticated())) { - return SendErrorResponse("Not Authenticated"); + return RpcResponse::fail(request, "Not Authenticated"); } - HandlerResponse (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]); + RpcMethodHandler handlerFunc = messageMap[request.methodName()]; if (!handlerFunc) { - return SendErrorResponse("invalid request type"); + return RpcResponse::fail(request, "invalid request type"); } - return handlerFunc(this); -} - -WSRequestHandler::~WSRequestHandler() { -} - -HandlerResponse WSRequestHandler::SendOKResponse(obs_data_t* additionalFields) { - return SendResponse("ok", additionalFields); -} - -HandlerResponse WSRequestHandler::SendErrorResponse(QString errorMessage) { - OBSDataAutoRelease fields = obs_data_create(); - obs_data_set_string(fields, "error", errorMessage.toUtf8().constData()); - - return SendResponse("error", fields); -} - -HandlerResponse WSRequestHandler::SendErrorResponse(obs_data_t* additionalFields) { - return SendResponse("error", additionalFields); -} - -HandlerResponse WSRequestHandler::SendResponse(const char* status, obs_data_t* fields) { - obs_data_t* response = obs_data_create(); - obs_data_set_string(response, "message-id", _messageId); - obs_data_set_string(response, "status", status); - - if (fields) { - obs_data_apply(response, fields); - } - - return response; -} - -bool WSRequestHandler::hasField(QString name, obs_data_type expectedFieldType, obs_data_number_type expectedNumberType) { - if (!data || name.isEmpty() || name.isNull()) { - return false; - } - - OBSDataItemAutoRelease dataItem = obs_data_item_byname(data, name.toUtf8()); - if (!dataItem) { - return false; - } - - if (expectedFieldType != OBS_DATA_NULL) { - obs_data_type fieldType = obs_data_item_gettype(dataItem); - if (fieldType != expectedFieldType) { - return false; - } - - if (fieldType == OBS_DATA_NUMBER && expectedNumberType != OBS_DATA_NUM_INVALID) { - obs_data_number_type numberType = obs_data_item_numtype(dataItem); - if (numberType != expectedNumberType) { - return false; - } - } - } - - return true; -} - -bool WSRequestHandler::hasBool(QString fieldName) { - return this->hasField(fieldName, OBS_DATA_BOOLEAN); -} - -bool WSRequestHandler::hasString(QString fieldName) { - return this->hasField(fieldName, OBS_DATA_STRING); -} - -bool WSRequestHandler::hasNumber(QString fieldName, obs_data_number_type expectedNumberType) { - return this->hasField(fieldName, OBS_DATA_NUMBER, expectedNumberType); -} - -bool WSRequestHandler::hasInteger(QString fieldName) { - return this->hasNumber(fieldName, OBS_DATA_NUM_INT); -} - -bool WSRequestHandler::hasDouble(QString fieldName) { - return this->hasNumber(fieldName, OBS_DATA_NUM_DOUBLE); -} - -bool WSRequestHandler::hasArray(QString fieldName) { - return this->hasField(fieldName, OBS_DATA_ARRAY); -} - -bool WSRequestHandler::hasObject(QString fieldName) { - return this->hasField(fieldName, OBS_DATA_OBJECT); + return std::bind(handlerFunc, this, _1)(request); } diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index 0e729e55..da93330b 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -19,171 +19,146 @@ with this program. If not, see #pragma once +#include #include #include -#include -#include -#include #include #include #include "ConnectionProperties.h" +#include "rpc/RpcRequest.h" +#include "rpc/RpcResponse.h" + #include "obs-websocket.h" -typedef obs_data_t* HandlerResponse; - -class WSRequestHandler : public QObject { - Q_OBJECT +class WSRequestHandler; +typedef RpcResponse(WSRequestHandler::*RpcMethodHandler)(const RpcRequest&); +class WSRequestHandler { public: explicit WSRequestHandler(ConnectionProperties& connProperties); - ~WSRequestHandler(); - std::string processIncomingMessage(std::string& textMessage); - - bool hasField(QString fieldName, obs_data_type expectedFieldType = OBS_DATA_NULL, - obs_data_number_type expectedNumberType = OBS_DATA_NUM_INVALID); - bool hasBool(QString fieldName); - bool hasString(QString fieldName); - bool hasNumber(QString fieldName, obs_data_number_type expectedNumberType = OBS_DATA_NUM_INVALID); - bool hasInteger(QString fieldName); - bool hasDouble(QString fieldName); - bool hasArray(QString fieldName); - bool hasObject(QString fieldName); - - HandlerResponse SendOKResponse(obs_data_t* additionalFields = nullptr); - HandlerResponse SendErrorResponse(QString errorMessage); - HandlerResponse SendErrorResponse(obs_data_t* additionalFields = nullptr); - HandlerResponse SendResponse(const char* status, obs_data_t* additionalFields = nullptr); - - obs_data_t* parameters() { - return this->data; - } + RpcResponse processRequest(const RpcRequest& textMessage); private: - const char* _messageId; - const char* _requestType; ConnectionProperties& _connProperties; - OBSDataAutoRelease data; - HandlerResponse processRequest(std::string& textMessage); + static const QHash messageMap; + static const QSet authNotRequired; - static QHash messageMap; - static QSet authNotRequired; + RpcResponse GetVersion(const RpcRequest&); + RpcResponse GetAuthRequired(const RpcRequest&); + RpcResponse Authenticate(const RpcRequest&); - static HandlerResponse HandleGetVersion(WSRequestHandler* req); - static HandlerResponse HandleGetAuthRequired(WSRequestHandler* req); - static HandlerResponse HandleAuthenticate(WSRequestHandler* req); + RpcResponse GetStats(const RpcRequest&); + RpcResponse SetHeartbeat(const RpcRequest&); + RpcResponse GetVideoInfo(const RpcRequest&); - static HandlerResponse HandleGetStats(WSRequestHandler* req); - static HandlerResponse HandleSetHeartbeat(WSRequestHandler* req); - static HandlerResponse HandleGetVideoInfo(WSRequestHandler* req); + RpcResponse SetFilenameFormatting(const RpcRequest&); + RpcResponse GetFilenameFormatting(const RpcRequest&); - static HandlerResponse HandleSetFilenameFormatting(WSRequestHandler* req); - static HandlerResponse HandleGetFilenameFormatting(WSRequestHandler* req); + RpcResponse BroadcastCustomMessage(const RpcRequest&); - static HandlerResponse HandleBroadcastCustomMessage(WSRequestHandler* req); + RpcResponse SetCurrentScene(const RpcRequest&); + RpcResponse GetCurrentScene(const RpcRequest&); + RpcResponse GetSceneList(const RpcRequest&); - static HandlerResponse HandleSetCurrentScene(WSRequestHandler* req); - static HandlerResponse HandleGetCurrentScene(WSRequestHandler* req); - static HandlerResponse HandleGetSceneList(WSRequestHandler* req); + RpcResponse SetSceneItemRender(const RpcRequest&); + RpcResponse SetSceneItemPosition(const RpcRequest&); + RpcResponse SetSceneItemTransform(const RpcRequest&); + RpcResponse SetSceneItemCrop(const RpcRequest&); + RpcResponse GetSceneItemProperties(const RpcRequest&); + RpcResponse SetSceneItemProperties(const RpcRequest&); + RpcResponse ResetSceneItem(const RpcRequest&); + RpcResponse DuplicateSceneItem(const RpcRequest&); + RpcResponse DeleteSceneItem(const RpcRequest&); + RpcResponse ReorderSceneItems(const RpcRequest&); - static HandlerResponse HandleSetSceneItemRender(WSRequestHandler* req); - static HandlerResponse HandleSetSceneItemPosition(WSRequestHandler* req); - static HandlerResponse HandleSetSceneItemTransform(WSRequestHandler* req); - static HandlerResponse HandleSetSceneItemCrop(WSRequestHandler* req); - static HandlerResponse HandleGetSceneItemProperties(WSRequestHandler* req); - static HandlerResponse HandleSetSceneItemProperties(WSRequestHandler* req); - static HandlerResponse HandleResetSceneItem(WSRequestHandler* req); - static HandlerResponse HandleDuplicateSceneItem(WSRequestHandler* req); - static HandlerResponse HandleDeleteSceneItem(WSRequestHandler* req); - static HandlerResponse HandleReorderSceneItems(WSRequestHandler* req); + RpcResponse GetStreamingStatus(const RpcRequest&); + RpcResponse StartStopStreaming(const RpcRequest&); + RpcResponse StartStopRecording(const RpcRequest&); - static HandlerResponse HandleGetStreamingStatus(WSRequestHandler* req); - static HandlerResponse HandleStartStopStreaming(WSRequestHandler* req); - static HandlerResponse HandleStartStopRecording(WSRequestHandler* req); + RpcResponse StartStreaming(const RpcRequest&); + RpcResponse StopStreaming(const RpcRequest&); - static HandlerResponse HandleStartStreaming(WSRequestHandler* req); - static HandlerResponse HandleStopStreaming(WSRequestHandler* req); + RpcResponse StartRecording(const RpcRequest&); + RpcResponse StopRecording(const RpcRequest&); + RpcResponse PauseRecording(const RpcRequest&); + RpcResponse ResumeRecording(const RpcRequest&); - static HandlerResponse HandleStartRecording(WSRequestHandler* req); - static HandlerResponse HandleStopRecording(WSRequestHandler* req); - static HandlerResponse HandlePauseRecording(WSRequestHandler* req); - static HandlerResponse HandleResumeRecording(WSRequestHandler* req); + RpcResponse StartStopReplayBuffer(const RpcRequest&); + RpcResponse StartReplayBuffer(const RpcRequest&); + RpcResponse StopReplayBuffer(const RpcRequest&); + RpcResponse SaveReplayBuffer(const RpcRequest&); - static HandlerResponse HandleStartStopReplayBuffer(WSRequestHandler* req); - static HandlerResponse HandleStartReplayBuffer(WSRequestHandler* req); - static HandlerResponse HandleStopReplayBuffer(WSRequestHandler* req); - static HandlerResponse HandleSaveReplayBuffer(WSRequestHandler* req); + RpcResponse SetRecordingFolder(const RpcRequest&); + RpcResponse GetRecordingFolder(const RpcRequest&); - static HandlerResponse HandleSetRecordingFolder(WSRequestHandler* req); - static HandlerResponse HandleGetRecordingFolder(WSRequestHandler* req); + RpcResponse GetTransitionList(const RpcRequest&); + RpcResponse GetCurrentTransition(const RpcRequest&); + RpcResponse SetCurrentTransition(const RpcRequest&); - static HandlerResponse HandleGetTransitionList(WSRequestHandler* req); - static HandlerResponse HandleGetCurrentTransition(WSRequestHandler* req); - static HandlerResponse HandleSetCurrentTransition(WSRequestHandler* req); + RpcResponse SetVolume(const RpcRequest&); + RpcResponse GetVolume(const RpcRequest&); + RpcResponse ToggleMute(const RpcRequest&); + RpcResponse SetMute(const RpcRequest&); + RpcResponse GetMute(const RpcRequest&); + RpcResponse SetSyncOffset(const RpcRequest&); + RpcResponse GetSyncOffset(const RpcRequest&); + RpcResponse GetSpecialSources(const RpcRequest&); + RpcResponse GetSourcesList(const RpcRequest&); + RpcResponse GetSourceTypesList(const RpcRequest&); + RpcResponse GetSourceSettings(const RpcRequest&); + RpcResponse SetSourceSettings(const RpcRequest&); + RpcResponse TakeSourceScreenshot(const RpcRequest&); - static HandlerResponse HandleSetVolume(WSRequestHandler* req); - static HandlerResponse HandleGetVolume(WSRequestHandler* req); - static HandlerResponse HandleToggleMute(WSRequestHandler* req); - static HandlerResponse HandleSetMute(WSRequestHandler* req); - static HandlerResponse HandleGetMute(WSRequestHandler* req); - static HandlerResponse HandleSetSyncOffset(WSRequestHandler* req); - static HandlerResponse HandleGetSyncOffset(WSRequestHandler* req); - static HandlerResponse HandleGetSpecialSources(WSRequestHandler* req); - static HandlerResponse HandleGetSourcesList(WSRequestHandler* req); - static HandlerResponse HandleGetSourceTypesList(WSRequestHandler* req); - static HandlerResponse HandleGetSourceSettings(WSRequestHandler* req); - static HandlerResponse HandleSetSourceSettings(WSRequestHandler* req); - static HandlerResponse HandleTakeSourceScreenshot(WSRequestHandler* req); + RpcResponse GetSourceFilters(const RpcRequest&); + RpcResponse GetSourceFilterInfo(const RpcRequest&); + RpcResponse AddFilterToSource(const RpcRequest&); + RpcResponse RemoveFilterFromSource(const RpcRequest&); + RpcResponse ReorderSourceFilter(const RpcRequest&); + RpcResponse MoveSourceFilter(const RpcRequest&); + RpcResponse SetSourceFilterSettings(const RpcRequest&); + RpcResponse SetSourceFilterVisibility(const RpcRequest&); - static HandlerResponse HandleGetSourceFilters(WSRequestHandler* req); - static HandlerResponse HandleGetSourceFilterInfo(WSRequestHandler* req); - static HandlerResponse HandleAddFilterToSource(WSRequestHandler* req); - static HandlerResponse HandleRemoveFilterFromSource(WSRequestHandler* req); - static HandlerResponse HandleReorderSourceFilter(WSRequestHandler* req); - static HandlerResponse HandleMoveSourceFilter(WSRequestHandler* req); - static HandlerResponse HandleSetSourceFilterSettings(WSRequestHandler* req); - static HandlerResponse HandleSetSourceFilterVisibility(WSRequestHandler* req); + RpcResponse SetCurrentSceneCollection(const RpcRequest&); + RpcResponse GetCurrentSceneCollection(const RpcRequest&); + RpcResponse ListSceneCollections(const RpcRequest&); - static HandlerResponse HandleSetCurrentSceneCollection(WSRequestHandler* req); - static HandlerResponse HandleGetCurrentSceneCollection(WSRequestHandler* req); - static HandlerResponse HandleListSceneCollections(WSRequestHandler* req); + RpcResponse SetCurrentProfile(const RpcRequest&); + RpcResponse GetCurrentProfile(const RpcRequest&); + RpcResponse ListProfiles(const RpcRequest&); - static HandlerResponse HandleSetCurrentProfile(WSRequestHandler* req); - static HandlerResponse HandleGetCurrentProfile(WSRequestHandler* req); - static HandlerResponse HandleListProfiles(WSRequestHandler* req); - - static HandlerResponse HandleSetStreamSettings(WSRequestHandler* req); - static HandlerResponse HandleGetStreamSettings(WSRequestHandler* req); - static HandlerResponse HandleSaveStreamSettings(WSRequestHandler* req); + RpcResponse SetStreamSettings(const RpcRequest&); + RpcResponse GetStreamSettings(const RpcRequest&); + RpcResponse SaveStreamSettings(const RpcRequest&); #if BUILD_CAPTIONS - static HandlerResponse HandleSendCaptions(WSRequestHandler * req); + RpcResponse SendCaptions(const RpcRequest&); #endif - static HandlerResponse HandleSetTransitionDuration(WSRequestHandler* req); - static HandlerResponse HandleGetTransitionDuration(WSRequestHandler* req); + RpcResponse SetTransitionDuration(const RpcRequest&); + RpcResponse GetTransitionDuration(const RpcRequest&); - static HandlerResponse HandleGetStudioModeStatus(WSRequestHandler* req); - static HandlerResponse HandleGetPreviewScene(WSRequestHandler* req); - static HandlerResponse HandleSetPreviewScene(WSRequestHandler* req); - static HandlerResponse HandleTransitionToProgram(WSRequestHandler* req); - static HandlerResponse HandleEnableStudioMode(WSRequestHandler* req); - static HandlerResponse HandleDisableStudioMode(WSRequestHandler* req); - static HandlerResponse HandleToggleStudioMode(WSRequestHandler* req); + RpcResponse GetStudioModeStatus(const RpcRequest&); + RpcResponse GetPreviewScene(const RpcRequest&); + RpcResponse SetPreviewScene(const RpcRequest&); + RpcResponse TransitionToProgram(const RpcRequest&); + RpcResponse EnableStudioMode(const RpcRequest&); + RpcResponse DisableStudioMode(const RpcRequest&); + RpcResponse ToggleStudioMode(const RpcRequest&); - static HandlerResponse HandleSetTextGDIPlusProperties(WSRequestHandler* req); - static HandlerResponse HandleGetTextGDIPlusProperties(WSRequestHandler* req); + RpcResponse SetTextGDIPlusProperties(const RpcRequest&); + RpcResponse GetTextGDIPlusProperties(const RpcRequest&); - static HandlerResponse HandleSetTextFreetype2Properties(WSRequestHandler* req); - static HandlerResponse HandleGetTextFreetype2Properties(WSRequestHandler* req); + RpcResponse SetTextFreetype2Properties(const RpcRequest&); + RpcResponse GetTextFreetype2Properties(const RpcRequest&); - static HandlerResponse HandleSetBrowserSourceProperties(WSRequestHandler* req); - static HandlerResponse HandleGetBrowserSourceProperties(WSRequestHandler* req); + RpcResponse SetBrowserSourceProperties(const RpcRequest&); + RpcResponse GetBrowserSourceProperties(const RpcRequest&); - static HandlerResponse HandleListOutputs(WSRequestHandler* req); - static HandlerResponse HandleGetOutputInfo(WSRequestHandler* req); - static HandlerResponse HandleStartOutput(WSRequestHandler* req); - static HandlerResponse HandleStopOutput(WSRequestHandler* req); + RpcResponse ListOutputs(const RpcRequest&); + RpcResponse GetOutputInfo(const RpcRequest&); + RpcResponse StartOutput(const RpcRequest&); + RpcResponse StopOutput(const RpcRequest&); }; diff --git a/src/WSRequestHandler_General.cpp b/src/WSRequestHandler_General.cpp index ecb3f48f..bab1a6e0 100644 --- a/src/WSRequestHandler_General.cpp +++ b/src/WSRequestHandler_General.cpp @@ -66,10 +66,10 @@ const char *describe_scale_type(int scale) { * @category general * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleGetVersion(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetVersion(const RpcRequest& request) { QString obsVersion = Utils::OBSVersionString(); - QList names = req->messageMap.keys(); + QList names = messageMap.keys(); names.sort(Qt::CaseInsensitive); // (Palakis) OBS' data arrays only support object arrays, so I improvised. @@ -85,7 +85,7 @@ HandlerResponse WSRequestHandler::HandleGetVersion(WSRequestHandler* req) { obs_data_set_string(data, "obs-studio-version", obsVersion.toUtf8()); obs_data_set_string(data, "available-requests", requests.toUtf8()); - return req->SendOKResponse(data); + return request.success(data); } /** @@ -101,7 +101,7 @@ HandlerResponse WSRequestHandler::HandleGetVersion(WSRequestHandler* req) { * @category general * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleGetAuthRequired(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetAuthRequired(const RpcRequest& request) { bool authRequired = GetConfig()->AuthRequired; OBSDataAutoRelease data = obs_data_create(); @@ -115,7 +115,7 @@ HandlerResponse WSRequestHandler::HandleGetAuthRequired(WSRequestHandler* req) { config->Salt.toUtf8()); } - return req->SendOKResponse(data); + return request.success(data); } /** @@ -128,26 +128,26 @@ HandlerResponse WSRequestHandler::HandleGetAuthRequired(WSRequestHandler* req) { * @category general * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { - if (!req->hasField("auth")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::Authenticate(const RpcRequest& request) { + if (!request.hasField("auth")) { + return request.failed("missing request parameters"); } - if (req->_connProperties.isAuthenticated()) { - return req->SendErrorResponse("already authenticated"); + if (_connProperties.isAuthenticated()) { + return request.failed("already authenticated"); } - QString auth = obs_data_get_string(req->data, "auth"); + QString auth = obs_data_get_string(request.parameters(), "auth"); if (auth.isEmpty()) { - return req->SendErrorResponse("auth not specified!"); + return request.failed("auth not specified!"); } if (GetConfig()->CheckAuth(auth) == false) { - return req->SendErrorResponse("Authentication Failed."); + return request.failed("Authentication Failed."); } - req->_connProperties.setAuthenticated(true); - return req->SendOKResponse(); + _connProperties.setAuthenticated(true); + return request.success(); } /** @@ -160,17 +160,18 @@ HandlerResponse WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { * @category general * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleSetHeartbeat(WSRequestHandler* req) { - if (!req->hasField("enable")) { - return req->SendErrorResponse("Heartbeat parameter missing"); +RpcResponse WSRequestHandler::SetHeartbeat(const RpcRequest& request) { + if (!request.hasField("enable")) { + return request.failed("Heartbeat parameter missing"); } auto events = GetEventsSystem(); - events->HeartbeatIsActive = obs_data_get_bool(req->data, "enable"); + events->HeartbeatIsActive = obs_data_get_bool(request.parameters(), "enable"); OBSDataAutoRelease response = obs_data_create(); obs_data_set_bool(response, "enable", events->HeartbeatIsActive); - return req->SendOKResponse(response); + + return request.success(response); } /** @@ -183,18 +184,19 @@ HandlerResponse WSRequestHandler::HandleSetHeartbeat(WSRequestHandler* req) { * @category general * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleSetFilenameFormatting(WSRequestHandler* req) { - if (!req->hasField("filename-formatting")) { - return req->SendErrorResponse(" parameter missing"); +RpcResponse WSRequestHandler::SetFilenameFormatting(const RpcRequest& request) { + if (!request.hasField("filename-formatting")) { + return request.failed(" parameter missing"); } - QString filenameFormatting = obs_data_get_string(req->data, "filename-formatting"); + QString filenameFormatting = obs_data_get_string(request.parameters(), "filename-formatting"); if (filenameFormatting.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } Utils::SetFilenameFormatting(filenameFormatting.toUtf8()); - return req->SendOKResponse(); + + return request.success(); } /** @@ -207,10 +209,11 @@ HandlerResponse WSRequestHandler::HandleSetFilenameFormatting(WSRequestHandler* * @category general * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleGetFilenameFormatting(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetFilenameFormatting(const RpcRequest& request) { OBSDataAutoRelease response = obs_data_create(); obs_data_set_string(response, "filename-formatting", Utils::GetFilenameFormatting()); - return req->SendOKResponse(response); + + return request.success(response); } /** @@ -223,12 +226,13 @@ HandlerResponse WSRequestHandler::HandleGetFilenameFormatting(WSRequestHandler* * @category general * @since 4.6.0 */ -HandlerResponse WSRequestHandler::HandleGetStats(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetStats(const RpcRequest& request) { OBSDataAutoRelease stats = GetEventsSystem()->GetStats(); OBSDataAutoRelease response = obs_data_create(); obs_data_set_obj(response, "stats", stats); - return req->SendOKResponse(response); + + return request.success(response); } /** @@ -242,26 +246,26 @@ HandlerResponse WSRequestHandler::HandleGetStats(WSRequestHandler* req) { * @category general * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleBroadcastCustomMessage(WSRequestHandler* req) { - if (!req->hasField("realm") || !req->hasField("data")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::BroadcastCustomMessage(const RpcRequest& request) { + if (!request.hasField("realm") || !request.hasField("data")) { + return request.failed("missing request parameters"); } - QString realm = obs_data_get_string(req->data, "realm"); - OBSDataAutoRelease data = obs_data_get_obj(req->data, "data"); + QString realm = obs_data_get_string(request.parameters(), "realm"); + OBSDataAutoRelease data = obs_data_get_obj(request.parameters(), "data"); if (realm.isEmpty()) { - return req->SendErrorResponse("realm not specified!"); + return request.failed("realm not specified!"); } if (!data) { - return req->SendErrorResponse("data not specified!"); + return request.failed("data not specified!"); } auto events = GetEventsSystem(); events->OnBroadcastCustomMessage(realm, data); - return req->SendOKResponse(); + return request.success(); } @@ -283,9 +287,10 @@ HandlerResponse WSRequestHandler::HandleBroadcastCustomMessage(WSRequestHandler* * @category general * @since 4.6.0 */ -HandlerResponse WSRequestHandler::HandleGetVideoInfo(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetVideoInfo(const RpcRequest& request) { obs_video_info ovi; obs_get_video_info(&ovi); + OBSDataAutoRelease response = obs_data_create(); obs_data_set_int(response, "baseWidth", ovi.base_width); obs_data_set_int(response, "baseHeight", ovi.base_height); @@ -296,5 +301,6 @@ HandlerResponse WSRequestHandler::HandleGetVideoInfo(WSRequestHandler* req) { obs_data_set_string(response, "colorSpace", describe_color_space(ovi.colorspace)); obs_data_set_string(response, "colorRange", describe_color_range(ovi.range)); obs_data_set_string(response, "scaleType", describe_scale_type(ovi.scale_type)); - return req->SendOKResponse(response); + + return request.success(response); } diff --git a/src/WSRequestHandler_Outputs.cpp b/src/WSRequestHandler_Outputs.cpp index 45469411..dad0bf19 100644 --- a/src/WSRequestHandler_Outputs.cpp +++ b/src/WSRequestHandler_Outputs.cpp @@ -1,3 +1,5 @@ +#include + #include "WSRequestHandler.h" /** @@ -57,16 +59,16 @@ obs_data_t* getOutputInfo(obs_output_t* output) return data; } -HandlerResponse findOutputOrFail(WSRequestHandler* req, std::function callback) +RpcResponse findOutputOrFail(const RpcRequest& request, std::function callback) { - if (!req->hasField("outputName")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("outputName")) { + return request.failed("missing request parameters"); } - const char* outputName = obs_data_get_string(req->parameters(), "outputName"); + const char* outputName = obs_data_get_string(request.parameters(), "outputName"); OBSOutputAutoRelease output = obs_get_output_by_name(outputName); if (!output) { - return req->SendErrorResponse("specified output doesn't exist"); + return request.failed("specified output doesn't exist"); } return callback(output); @@ -82,7 +84,7 @@ HandlerResponse findOutputOrFail(WSRequestHandler* req, std::functionSendOKResponse(fields); + + return request.success(fields); } /** @@ -112,14 +115,14 @@ HandlerResponse WSRequestHandler::HandleListOutputs(WSRequestHandler* req) * @category outputs * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleGetOutputInfo(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetOutputInfo(const RpcRequest& request) { - return findOutputOrFail(req, [req](obs_output_t* output) { + return findOutputOrFail(request, [request](obs_output_t* output) { OBSDataAutoRelease outputInfo = getOutputInfo(output); OBSDataAutoRelease fields = obs_data_create(); obs_data_set_obj(fields, "outputInfo", outputInfo); - return req->SendOKResponse(fields); + return request.success(fields); }); } @@ -133,21 +136,21 @@ HandlerResponse WSRequestHandler::HandleGetOutputInfo(WSRequestHandler* req) * @category outputs * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleStartOutput(WSRequestHandler* req) +RpcResponse WSRequestHandler::StartOutput(const RpcRequest& request) { - return findOutputOrFail(req, [req](obs_output_t* output) { + return findOutputOrFail(request, [request](obs_output_t* output) { if (obs_output_active(output)) { - return req->SendErrorResponse("output already active"); + return request.failed("output already active"); } bool success = obs_output_start(output); if (!success) { QString lastError = obs_output_get_last_error(output); QString errorMessage = QString("output start failed: %1").arg(lastError); - return req->SendErrorResponse(errorMessage); + return request.failed(errorMessage); } - return req->SendOKResponse(); + return request.success(); }); } @@ -162,20 +165,20 @@ HandlerResponse WSRequestHandler::HandleStartOutput(WSRequestHandler* req) * @category outputs * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleStopOutput(WSRequestHandler* req) +RpcResponse WSRequestHandler::StopOutput(const RpcRequest& request) { - return findOutputOrFail(req, [req](obs_output_t* output) { + return findOutputOrFail(request, [request](obs_output_t* output) { if (!obs_output_active(output)) { - return req->SendErrorResponse("output not active"); + return request.failed("output not active"); } - bool forceStop = obs_data_get_bool(req->data, "force"); + bool forceStop = obs_data_get_bool(request.parameters(), "force"); if (forceStop) { obs_output_force_stop(output); } else { obs_output_stop(output); } - return req->SendOKResponse(); + return request.success(); }); } diff --git a/src/WSRequestHandler_Profiles.cpp b/src/WSRequestHandler_Profiles.cpp index 3b78d40b..78e3ce2d 100644 --- a/src/WSRequestHandler_Profiles.cpp +++ b/src/WSRequestHandler_Profiles.cpp @@ -12,19 +12,19 @@ * @category profiles * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleSetCurrentProfile(WSRequestHandler* req) { - if (!req->hasField("profile-name")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetCurrentProfile(const RpcRequest& request) { + if (!request.hasField("profile-name")) { + return request.failed("missing request parameters"); } - QString profileName = obs_data_get_string(req->data, "profile-name"); + QString profileName = obs_data_get_string(request.parameters(), "profile-name"); if (profileName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } // TODO : check if profile exists obs_frontend_set_current_profile(profileName.toUtf8()); - return req->SendOKResponse(); + return request.success(); } /** @@ -37,12 +37,12 @@ HandlerResponse WSRequestHandler::HandleSetCurrentProfile(WSRequestHandler* req) * @category profiles * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleGetCurrentProfile(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetCurrentProfile(const RpcRequest& request) { OBSDataAutoRelease response = obs_data_create(); char* currentProfile = obs_frontend_get_current_profile(); obs_data_set_string(response, "profile-name", currentProfile); bfree(currentProfile); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -55,7 +55,7 @@ HandlerResponse WSRequestHandler::HandleGetCurrentProfile(WSRequestHandler* req) * @category profiles * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleListProfiles(WSRequestHandler* req) { +RpcResponse WSRequestHandler::ListProfiles(const RpcRequest& request) { char** profiles = obs_frontend_get_profiles(); OBSDataArrayAutoRelease list = Utils::StringListToArray(profiles, "profile-name"); bfree(profiles); @@ -63,5 +63,5 @@ HandlerResponse WSRequestHandler::HandleListProfiles(WSRequestHandler* req) { OBSDataAutoRelease response = obs_data_create(); obs_data_set_array(response, "profiles", list); - return req->SendOKResponse(response); + return request.success(response); } diff --git a/src/WSRequestHandler_Recording.cpp b/src/WSRequestHandler_Recording.cpp index 9164a404..330843d3 100644 --- a/src/WSRequestHandler_Recording.cpp +++ b/src/WSRequestHandler_Recording.cpp @@ -1,16 +1,17 @@ #include "WSRequestHandler.h" +#include #include #include "Utils.h" -HandlerResponse ifCanPause(WSRequestHandler* req, std::function callback) +RpcResponse ifCanPause(const RpcRequest& request, std::function callback) { if (!obs_frontend_recording_active()) { - return req->SendErrorResponse("recording is not active"); + return request.failed("recording is not active"); } if (!Utils::RecordingPauseSupported()) { - return req->SendErrorResponse("recording pauses are not available in this version of OBS Studio"); + return request.failed("recording pauses are not available in this version of OBS Studio"); } return callback(); @@ -24,9 +25,9 @@ HandlerResponse ifCanPause(WSRequestHandler* req, std::functionSendOKResponse(); + return request.success(); } /** @@ -38,13 +39,13 @@ HandlerResponse WSRequestHandler::HandleStartStopRecording(WSRequestHandler* req * @category recording * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleStartRecording(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StartRecording(const RpcRequest& request) { if (obs_frontend_recording_active()) { - return req->SendErrorResponse("recording already active"); + return request.failed("recording already active"); } obs_frontend_recording_start(); - return req->SendOKResponse(); + return request.success(); } /** @@ -56,13 +57,13 @@ HandlerResponse WSRequestHandler::HandleStartRecording(WSRequestHandler* req) { * @category recording * @since 4.1.0 */ - HandlerResponse WSRequestHandler::HandleStopRecording(WSRequestHandler* req) { + RpcResponse WSRequestHandler::StopRecording(const RpcRequest& request) { if (!obs_frontend_recording_active()) { - return req->SendErrorResponse("recording not active"); + return request.failed("recording not active"); } obs_frontend_recording_stop(); - return req->SendOKResponse(); + return request.success(); } /** @@ -74,14 +75,14 @@ HandlerResponse WSRequestHandler::HandleStartRecording(WSRequestHandler* req) { * @category recording * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandlePauseRecording(WSRequestHandler* req) { - return ifCanPause(req, [req]() { +RpcResponse WSRequestHandler::PauseRecording(const RpcRequest& request) { + return ifCanPause(request, [request]() { if (Utils::RecordingPaused()) { - return req->SendErrorResponse("recording already paused"); + return request.failed("recording already paused"); } Utils::PauseRecording(true); - return req->SendOKResponse(); + return request.success(); }); } @@ -94,14 +95,14 @@ HandlerResponse WSRequestHandler::HandlePauseRecording(WSRequestHandler* req) { * @category recording * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleResumeRecording(WSRequestHandler* req) { - return ifCanPause(req, [req]() { +RpcResponse WSRequestHandler::ResumeRecording(const RpcRequest& request) { + return ifCanPause(request, [request]() { if (!Utils::RecordingPaused()) { - return req->SendErrorResponse("recording is not paused"); + return request.failed("recording is not paused"); } Utils::PauseRecording(false); - return req->SendOKResponse(); + return request.success(); }); } @@ -120,18 +121,18 @@ HandlerResponse WSRequestHandler::HandleResumeRecording(WSRequestHandler* req) { * @category recording * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleSetRecordingFolder(WSRequestHandler* req) { - if (!req->hasField("rec-folder")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetRecordingFolder(const RpcRequest& request) { + if (!request.hasField("rec-folder")) { + return request.failed("missing request parameters"); } - const char* newRecFolder = obs_data_get_string(req->data, "rec-folder"); + const char* newRecFolder = obs_data_get_string(request.parameters(), "rec-folder"); bool success = Utils::SetRecordingFolder(newRecFolder); if (!success) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - return req->SendOKResponse(); + return request.success(); } /** @@ -144,11 +145,11 @@ HandlerResponse WSRequestHandler::HandleSetRecordingFolder(WSRequestHandler* req * @category recording * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetRecordingFolder(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetRecordingFolder(const RpcRequest& request) { const char* recFolder = Utils::GetRecordingFolder(); OBSDataAutoRelease response = obs_data_create(); obs_data_set_string(response, "rec-folder", recFolder); - return req->SendOKResponse(response); + return request.success(response); } diff --git a/src/WSRequestHandler_ReplayBuffer.cpp b/src/WSRequestHandler_ReplayBuffer.cpp index 86add84a..510b8f05 100644 --- a/src/WSRequestHandler_ReplayBuffer.cpp +++ b/src/WSRequestHandler_ReplayBuffer.cpp @@ -10,13 +10,13 @@ * @category replay buffer * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleStartStopReplayBuffer(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StartStopReplayBuffer(const RpcRequest& request) { if (obs_frontend_replay_buffer_active()) { obs_frontend_replay_buffer_stop(); } else { Utils::StartReplayBuffer(); } - return req->SendOKResponse(); + return request.success(); } /** @@ -31,17 +31,17 @@ HandlerResponse WSRequestHandler::HandleStartStopReplayBuffer(WSRequestHandler* * @category replay buffer * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleStartReplayBuffer(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StartReplayBuffer(const RpcRequest& request) { if (!Utils::ReplayBufferEnabled()) { - return req->SendErrorResponse("replay buffer disabled in settings"); + return request.failed("replay buffer disabled in settings"); } if (obs_frontend_replay_buffer_active() == true) { - return req->SendErrorResponse("replay buffer already active"); + return request.failed("replay buffer already active"); } Utils::StartReplayBuffer(); - return req->SendOKResponse(); + return request.success(); } /** @@ -53,12 +53,12 @@ HandlerResponse WSRequestHandler::HandleStartReplayBuffer(WSRequestHandler* req) * @category replay buffer * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleStopReplayBuffer(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StopReplayBuffer(const RpcRequest& request) { if (obs_frontend_replay_buffer_active() == true) { obs_frontend_replay_buffer_stop(); - return req->SendOKResponse(); + return request.success(); } else { - return req->SendErrorResponse("replay buffer not active"); + return request.failed("replay buffer not active"); } } @@ -72,9 +72,9 @@ HandlerResponse WSRequestHandler::HandleStopReplayBuffer(WSRequestHandler* req) * @category replay buffer * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleSaveReplayBuffer(WSRequestHandler* req) { +RpcResponse WSRequestHandler::SaveReplayBuffer(const RpcRequest& request) { if (!obs_frontend_replay_buffer_active()) { - return req->SendErrorResponse("replay buffer not active"); + return request.failed("replay buffer not active"); } OBSOutputAutoRelease replayOutput = obs_frontend_get_replay_buffer_output(); @@ -84,5 +84,5 @@ HandlerResponse WSRequestHandler::HandleSaveReplayBuffer(WSRequestHandler* req) proc_handler_call(ph, "save", &cd); calldata_free(&cd); - return req->SendOKResponse(); + return request.success(); } diff --git a/src/WSRequestHandler_SceneCollections.cpp b/src/WSRequestHandler_SceneCollections.cpp index ccc411a1..1f87996b 100644 --- a/src/WSRequestHandler_SceneCollections.cpp +++ b/src/WSRequestHandler_SceneCollections.cpp @@ -12,19 +12,19 @@ * @category scene collections * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleSetCurrentSceneCollection(WSRequestHandler* req) { - if (!req->hasField("sc-name")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetCurrentSceneCollection(const RpcRequest& request) { + if (!request.hasField("sc-name")) { + return request.failed("missing request parameters"); } - QString sceneCollection = obs_data_get_string(req->data, "sc-name"); + QString sceneCollection = obs_data_get_string(request.parameters(), "sc-name"); if (sceneCollection.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } // TODO : Check if specified profile exists and if changing is allowed obs_frontend_set_current_scene_collection(sceneCollection.toUtf8()); - return req->SendOKResponse(); + return request.success(); } /** @@ -37,14 +37,14 @@ HandlerResponse WSRequestHandler::HandleSetCurrentSceneCollection(WSRequestHandl * @category scene collections * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleGetCurrentSceneCollection(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetCurrentSceneCollection(const RpcRequest& request) { OBSDataAutoRelease response = obs_data_create(); char* sceneCollection = obs_frontend_get_current_scene_collection(); obs_data_set_string(response, "sc-name", sceneCollection); bfree(sceneCollection); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -57,7 +57,7 @@ HandlerResponse WSRequestHandler::HandleGetCurrentSceneCollection(WSRequestHandl * @category scene collections * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleListSceneCollections(WSRequestHandler* req) { +RpcResponse WSRequestHandler::ListSceneCollections(const RpcRequest& request) { char** sceneCollections = obs_frontend_get_scene_collections(); OBSDataArrayAutoRelease list = Utils::StringListToArray(sceneCollections, "sc-name"); @@ -66,5 +66,5 @@ HandlerResponse WSRequestHandler::HandleListSceneCollections(WSRequestHandler* r OBSDataAutoRelease response = obs_data_create(); obs_data_set_array(response, "scene-collections", list); - return req->SendOKResponse(response); + return request.success(response); } diff --git a/src/WSRequestHandler_SceneItems.cpp b/src/WSRequestHandler_SceneItems.cpp index e2e6d188..cd54de16 100644 --- a/src/WSRequestHandler_SceneItems.cpp +++ b/src/WSRequestHandler_SceneItems.cpp @@ -38,31 +38,31 @@ * @category scene items * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleGetSceneItemProperties(WSRequestHandler* req) { - if (!req->hasField("item")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::GetSceneItemProperties(const RpcRequest& request) { + if (!request.hasField("item")) { + return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(req->data, "item"); + QString itemName = obs_data_get_string(request.parameters(), "item"); if (itemName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - QString sceneName = obs_data_get_string(req->data, "scene-name"); + QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } OBSDataAutoRelease data = Utils::GetSceneItemPropertiesData(sceneItem); obs_data_set_string(data, "name", itemName.toUtf8()); - return req->SendOKResponse(data); + return request.success(data); } /** @@ -93,38 +93,38 @@ HandlerResponse WSRequestHandler::HandleGetSceneItemProperties(WSRequestHandler* * @category scene items * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* req) { - if (!req->hasField("item")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) { + if (!request.hasField("item")) { + return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(req->data, "item"); + QString itemName = obs_data_get_string(request.parameters(), "item"); if (itemName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - QString sceneName = obs_data_get_string(req->data, "scene-name"); + QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } bool badRequest = false; - OBSDataAutoRelease errorMessage = obs_data_create(); + OBSDataAutoRelease errorData = obs_data_create(); obs_sceneitem_defer_update_begin(sceneItem); - if (req->hasField("position")) { + if (request.hasField("position")) { vec2 oldPosition; OBSDataAutoRelease positionError = obs_data_create(); obs_sceneitem_get_pos(sceneItem, &oldPosition); - OBSDataAutoRelease reqPosition = obs_data_get_obj(req->data, "position"); + OBSDataAutoRelease reqPosition = obs_data_get_obj(request.parameters(), "position"); vec2 newPosition = oldPosition; if (obs_data_has_user_value(reqPosition, "x")) { newPosition.x = obs_data_get_int(reqPosition, "x"); @@ -140,20 +140,20 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* else { badRequest = true; obs_data_set_string(positionError, "alignment", "invalid"); - obs_data_set_obj(errorMessage, "position", positionError); + obs_data_set_obj(errorData, "position", positionError); } } obs_sceneitem_set_pos(sceneItem, &newPosition); } - if (req->hasField("rotation")) { - obs_sceneitem_set_rot(sceneItem, (float)obs_data_get_double(req->data, "rotation")); + if (request.hasField("rotation")) { + obs_sceneitem_set_rot(sceneItem, (float)obs_data_get_double(request.parameters(), "rotation")); } - if (req->hasField("scale")) { + if (request.hasField("scale")) { vec2 oldScale; obs_sceneitem_get_scale(sceneItem, &oldScale); - OBSDataAutoRelease reqScale = obs_data_get_obj(req->data, "scale"); + OBSDataAutoRelease reqScale = obs_data_get_obj(request.parameters(), "scale"); vec2 newScale = oldScale; if (obs_data_has_user_value(reqScale, "x")) { newScale.x = obs_data_get_double(reqScale, "x"); @@ -164,10 +164,10 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* obs_sceneitem_set_scale(sceneItem, &newScale); } - if (req->hasField("crop")) { + if (request.hasField("crop")) { obs_sceneitem_crop oldCrop; obs_sceneitem_get_crop(sceneItem, &oldCrop); - OBSDataAutoRelease reqCrop = obs_data_get_obj(req->data, "crop"); + OBSDataAutoRelease reqCrop = obs_data_get_obj(request.parameters(), "crop"); obs_sceneitem_crop newCrop = oldCrop; if (obs_data_has_user_value(reqCrop, "top")) { newCrop.top = obs_data_get_int(reqCrop, "top"); @@ -184,18 +184,18 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* obs_sceneitem_set_crop(sceneItem, &newCrop); } - if (req->hasField("visible")) { - obs_sceneitem_set_visible(sceneItem, obs_data_get_bool(req->data, "visible")); + if (request.hasField("visible")) { + obs_sceneitem_set_visible(sceneItem, obs_data_get_bool(request.parameters(), "visible")); } - if (req->hasField("locked")) { - obs_sceneitem_set_locked(sceneItem, obs_data_get_bool(req->data, "locked")); + if (request.hasField("locked")) { + obs_sceneitem_set_locked(sceneItem, obs_data_get_bool(request.parameters(), "locked")); } - if (req->hasField("bounds")) { + if (request.hasField("bounds")) { bool badBounds = false; OBSDataAutoRelease boundsError = obs_data_create(); - OBSDataAutoRelease reqBounds = obs_data_get_obj(req->data, "bounds"); + OBSDataAutoRelease reqBounds = obs_data_get_obj(request.parameters(), "bounds"); if (obs_data_has_user_value(reqBounds, "type")) { QString newBoundsType = obs_data_get_string(reqBounds, "type"); if (newBoundsType == "OBS_BOUNDS_NONE") { @@ -245,17 +245,17 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* } } if (badBounds) { - obs_data_set_obj(errorMessage, "bounds", boundsError); + obs_data_set_obj(errorData, "bounds", boundsError); } } obs_sceneitem_defer_update_end(sceneItem); if (badRequest) { - return req->SendErrorResponse(errorMessage); + return request.failed("error", errorData); } - return req->SendOKResponse(); + return request.success(); } /** @@ -269,27 +269,27 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* * @category scene items * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleResetSceneItem(WSRequestHandler* req) { +RpcResponse WSRequestHandler::ResetSceneItem(const RpcRequest& request) { // TODO: remove this request, or refactor it to ResetSource - if (!req->hasField("item")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("item")) { + return request.failed("missing request parameters"); } - const char* itemName = obs_data_get_string(req->data, "item"); + const char* itemName = obs_data_get_string(request.parameters(), "item"); if (!itemName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - const char* sceneName = obs_data_get_string(req->data, "scene-name"); + const char* sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } OBSSource sceneItemSource = obs_sceneitem_get_source(sceneItem); @@ -297,7 +297,7 @@ HandlerResponse WSRequestHandler::HandleResetSceneItem(WSRequestHandler* req) { OBSDataAutoRelease settings = obs_source_get_settings(sceneItemSource); obs_source_update(sceneItemSource, settings); - return req->SendOKResponse(); + return request.success(); } /** @@ -313,34 +313,34 @@ HandlerResponse WSRequestHandler::HandleResetSceneItem(WSRequestHandler* req) { * @since 0.3 * @deprecated Since 4.3.0. Prefer the use of SetSceneItemProperties. */ -HandlerResponse WSRequestHandler::HandleSetSceneItemRender(WSRequestHandler* req) { - if (!req->hasField("source") || - !req->hasField("render")) +RpcResponse WSRequestHandler::SetSceneItemRender(const RpcRequest& request) { + if (!request.hasField("source") || + !request.hasField("render")) { - return req->SendErrorResponse("missing request parameters"); + return request.failed("missing request parameters"); } - const char* itemName = obs_data_get_string(req->data, "source"); - bool isVisible = obs_data_get_bool(req->data, "render"); + const char* itemName = obs_data_get_string(request.parameters(), "source"); + bool isVisible = obs_data_get_bool(request.parameters(), "render"); if (!itemName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - const char* sceneName = obs_data_get_string(req->data, "scene-name"); + const char* sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } obs_sceneitem_set_visible(sceneItem, isVisible); - return req->SendOKResponse(); + return request.success(); } /** @@ -358,34 +358,34 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemRender(WSRequestHandler* req * @since 4.0.0 * @deprecated Since 4.3.0. Prefer the use of SetSceneItemProperties. */ -HandlerResponse WSRequestHandler::HandleSetSceneItemPosition(WSRequestHandler* req) { - if (!req->hasField("item") || - !req->hasField("x") || !req->hasField("y")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetSceneItemPosition(const RpcRequest& request) { + if (!request.hasField("item") || + !request.hasField("x") || !request.hasField("y")) { + return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(req->data, "item"); + QString itemName = obs_data_get_string(request.parameters(), "item"); if (itemName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - QString sceneName = obs_data_get_string(req->data, "scene-name"); + QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene could not be found"); + return request.failed("requested scene could not be found"); } OBSSceneItem sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } vec2 item_position = { 0 }; - item_position.x = obs_data_get_double(req->data, "x"); - item_position.y = obs_data_get_double(req->data, "y"); + item_position.x = obs_data_get_double(request.parameters(), "x"); + item_position.y = obs_data_get_double(request.parameters(), "y"); obs_sceneitem_set_pos(sceneItem, &item_position); - return req->SendOKResponse(); + return request.success(); } /** @@ -403,34 +403,34 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemPosition(WSRequestHandler* r * @since 4.0.0 * @deprecated Since 4.3.0. Prefer the use of SetSceneItemProperties. */ -HandlerResponse WSRequestHandler::HandleSetSceneItemTransform(WSRequestHandler* req) { - if (!req->hasField("item") || - !req->hasField("x-scale") || - !req->hasField("y-scale") || - !req->hasField("rotation")) +RpcResponse WSRequestHandler::SetSceneItemTransform(const RpcRequest& request) { + if (!request.hasField("item") || + !request.hasField("x-scale") || + !request.hasField("y-scale") || + !request.hasField("rotation")) { - return req->SendErrorResponse("missing request parameters"); + return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(req->data, "item"); + QString itemName = obs_data_get_string(request.parameters(), "item"); if (itemName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - QString sceneName = obs_data_get_string(req->data, "scene-name"); + QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } vec2 scale; - scale.x = obs_data_get_double(req->data, "x-scale"); - scale.y = obs_data_get_double(req->data, "y-scale"); - float rotation = obs_data_get_double(req->data, "rotation"); + scale.x = obs_data_get_double(request.parameters(), "x-scale"); + scale.y = obs_data_get_double(request.parameters(), "y-scale"); + float rotation = obs_data_get_double(request.parameters(), "rotation"); OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } obs_sceneitem_defer_update_begin(sceneItem); @@ -440,7 +440,7 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemTransform(WSRequestHandler* obs_sceneitem_defer_update_end(sceneItem); - return req->SendOKResponse(); + return request.success(); } /** @@ -459,36 +459,36 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemTransform(WSRequestHandler* * @since 4.1.0 * @deprecated Since 4.3.0. Prefer the use of SetSceneItemProperties. */ -HandlerResponse WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler* req) { - if (!req->hasField("item")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetSceneItemCrop(const RpcRequest& request) { + if (!request.hasField("item")) { + return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(req->data, "item"); + QString itemName = obs_data_get_string(request.parameters(), "item"); if (itemName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } - QString sceneName = obs_data_get_string(req->data, "scene-name"); + QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); if (!sceneItem) { - return req->SendErrorResponse("specified scene item doesn't exist"); + return request.failed("specified scene item doesn't exist"); } struct obs_sceneitem_crop crop = { 0 }; - crop.top = obs_data_get_int(req->data, "top"); - crop.bottom = obs_data_get_int(req->data, "bottom"); - crop.left = obs_data_get_int(req->data, "left"); - crop.right = obs_data_get_int(req->data, "right"); + crop.top = obs_data_get_int(request.parameters(), "top"); + crop.bottom = obs_data_get_int(request.parameters(), "bottom"); + crop.left = obs_data_get_int(request.parameters(), "left"); + crop.right = obs_data_get_int(request.parameters(), "right"); obs_sceneitem_set_crop(sceneItem, &crop); - return req->SendOKResponse(); + return request.success(); } /** @@ -504,38 +504,26 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler* req) * @category scene items * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleDeleteSceneItem(WSRequestHandler* req) { - if (!req->hasField("item")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::DeleteSceneItem(const RpcRequest& request) { + if (!request.hasField("item")) { + return request.failed("missing request parameters"); } - const char* sceneName = obs_data_get_string(req->data, "scene"); + const char* sceneName = obs_data_get_string(request.parameters(), "scene"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } - OBSDataAutoRelease item = obs_data_get_obj(req->data, "item"); + OBSDataAutoRelease item = obs_data_get_obj(request.parameters(), "item"); OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromItem(scene, item); if (!sceneItem) { - return req->SendErrorResponse("item with id/name combination not found in specified scene"); + return request.failed("item with id/name combination not found in specified scene"); } obs_sceneitem_remove(sceneItem); - return req->SendOKResponse(); -} - -struct DuplicateSceneItemData { - obs_sceneitem_t *referenceItem; - obs_source_t *fromSource; - obs_sceneitem_t *newItem; -}; - -static void DuplicateSceneItem(void *_data, obs_scene_t *scene) { - DuplicateSceneItemData *data = (DuplicateSceneItemData *)_data; - data->newItem = obs_scene_add(scene, data->fromSource); - obs_sceneitem_set_visible(data->newItem, obs_sceneitem_visible(data->referenceItem)); + return request.success(); } /** @@ -557,27 +545,33 @@ static void DuplicateSceneItem(void *_data, obs_scene_t *scene) { * @category scene items * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleDuplicateSceneItem(WSRequestHandler* req) { - if (!req->hasField("item")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::DuplicateSceneItem(const RpcRequest& request) { + struct DuplicateSceneItemData { + obs_sceneitem_t *referenceItem; + obs_source_t *fromSource; + obs_sceneitem_t *newItem; + }; + + if (!request.hasField("item")) { + return request.failed("missing request parameters"); } - const char* fromSceneName = obs_data_get_string(req->data, "fromScene"); + const char* fromSceneName = obs_data_get_string(request.parameters(), "fromScene"); OBSScene fromScene = Utils::GetSceneFromNameOrCurrent(fromSceneName); if (!fromScene) { - return req->SendErrorResponse("requested fromScene doesn't exist"); + return request.failed("requested fromScene doesn't exist"); } - const char* toSceneName = obs_data_get_string(req->data, "toScene"); + const char* toSceneName = obs_data_get_string(request.parameters(), "toScene"); OBSScene toScene = Utils::GetSceneFromNameOrCurrent(toSceneName); if (!toScene) { - return req->SendErrorResponse("requested toScene doesn't exist"); + return request.failed("requested toScene doesn't exist"); } - OBSDataAutoRelease item = obs_data_get_obj(req->data, "item"); + OBSDataAutoRelease item = obs_data_get_obj(request.parameters(), "item"); OBSSceneItemAutoRelease referenceItem = Utils::GetSceneItemFromItem(fromScene, item); if (!referenceItem) { - return req->SendErrorResponse("item with id/name combination not found in specified scene"); + return request.failed("item with id/name combination not found in specified scene"); } DuplicateSceneItemData data; @@ -585,12 +579,16 @@ HandlerResponse WSRequestHandler::HandleDuplicateSceneItem(WSRequestHandler* req data.referenceItem = referenceItem; obs_enter_graphics(); - obs_scene_atomic_update(toScene, DuplicateSceneItem, &data); + obs_scene_atomic_update(toScene, [](void *_data, obs_scene_t *scene) { + auto data = reinterpret_cast(_data); + data->newItem = obs_scene_add(scene, data->fromSource); + obs_sceneitem_set_visible(data->newItem, obs_sceneitem_visible(data->referenceItem)); + }, &data); obs_leave_graphics(); obs_sceneitem_t *newItem = data.newItem; if (!newItem) { - return req->SendErrorResponse("Error duplicating scene item"); + return request.failed("Error duplicating scene item"); } OBSDataAutoRelease itemData = obs_data_create(); @@ -601,5 +599,5 @@ HandlerResponse WSRequestHandler::HandleDuplicateSceneItem(WSRequestHandler* req obs_data_set_obj(responseData, "item", itemData); obs_data_set_string(responseData, "scene", obs_source_get_name(obs_scene_get_source(toScene))); - return req->SendOKResponse(responseData); + return request.success(responseData); } diff --git a/src/WSRequestHandler_Scenes.cpp b/src/WSRequestHandler_Scenes.cpp index 3a8754b4..9399ac5d 100644 --- a/src/WSRequestHandler_Scenes.cpp +++ b/src/WSRequestHandler_Scenes.cpp @@ -18,19 +18,19 @@ * @category scenes * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleSetCurrentScene(WSRequestHandler* req) { - if (!req->hasField("scene-name")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetCurrentScene(const RpcRequest& request) { + if (!request.hasField("scene-name")) { + return request.failed("missing request parameters"); } - const char* sceneName = obs_data_get_string(req->data, "scene-name"); + const char* sceneName = obs_data_get_string(request.parameters(), "scene-name"); OBSSourceAutoRelease source = obs_get_source_by_name(sceneName); if (source) { obs_frontend_set_current_scene(source); - return req->SendOKResponse(); + return request.success(); } else { - return req->SendErrorResponse("requested scene does not exist"); + return request.failed("requested scene does not exist"); } } @@ -45,7 +45,7 @@ HandlerResponse WSRequestHandler::HandleSetCurrentScene(WSRequestHandler* req) { * @category scenes * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleGetCurrentScene(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetCurrentScene(const RpcRequest& request) { OBSSourceAutoRelease currentScene = obs_frontend_get_current_scene(); OBSDataArrayAutoRelease sceneItems = Utils::GetSceneItems(currentScene); @@ -53,7 +53,7 @@ HandlerResponse WSRequestHandler::HandleGetCurrentScene(WSRequestHandler* req) { obs_data_set_string(data, "name", obs_source_get_name(currentScene)); obs_data_set_array(data, "sources", sceneItems); - return req->SendOKResponse(data); + return request.success(data); } /** @@ -67,7 +67,7 @@ HandlerResponse WSRequestHandler::HandleGetCurrentScene(WSRequestHandler* req) { * @category scenes * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleGetSceneList(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetSceneList(const RpcRequest& request) { OBSSourceAutoRelease currentScene = obs_frontend_get_current_scene(); OBSDataArrayAutoRelease scenes = Utils::GetScenes(); @@ -76,7 +76,7 @@ HandlerResponse WSRequestHandler::HandleGetSceneList(WSRequestHandler* req) { obs_source_get_name(currentScene)); obs_data_set_array(data, "scenes", scenes); - return req->SendOKResponse(data); + return request.success(data); } /** @@ -92,16 +92,16 @@ HandlerResponse WSRequestHandler::HandleGetSceneList(WSRequestHandler* req) { * @category scenes * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleReorderSceneItems(WSRequestHandler* req) { - QString sceneName = obs_data_get_string(req->data, "scene"); +RpcResponse WSRequestHandler::ReorderSceneItems(const RpcRequest& request) { + QString sceneName = obs_data_get_string(request.parameters(), "scene"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { - return req->SendErrorResponse("requested scene doesn't exist"); + return request.failed("requested scene doesn't exist"); } - OBSDataArrayAutoRelease items = obs_data_get_array(req->data, "items"); + OBSDataArrayAutoRelease items = obs_data_get_array(request.parameters(), "items"); if (!items) { - return req->SendErrorResponse("sceneItem order not specified"); + return request.failed("sceneItem order not specified"); } struct reorder_context { @@ -143,8 +143,8 @@ HandlerResponse WSRequestHandler::HandleReorderSceneItems(WSRequestHandler* req) }, &ctx); if (!ctx.success) { - return req->SendErrorResponse(ctx.errorMessage); + return request.failed(ctx.errorMessage); } - return req->SendOKResponse(); + return request.success(); } diff --git a/src/WSRequestHandler_Sources.cpp b/src/WSRequestHandler_Sources.cpp index 23207139..2feca185 100644 --- a/src/WSRequestHandler_Sources.cpp +++ b/src/WSRequestHandler_Sources.cpp @@ -21,7 +21,7 @@ * @category sources * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleGetSourcesList(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSourcesList(const RpcRequest& request) { OBSDataArrayAutoRelease sourcesArray = obs_data_array_create(); @@ -64,7 +64,7 @@ HandlerResponse WSRequestHandler::HandleGetSourcesList(WSRequestHandler* req) OBSDataAutoRelease response = obs_data_create(); obs_data_set_array(response, "sources", sourcesArray); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -89,7 +89,7 @@ HandlerResponse WSRequestHandler::HandleGetSourcesList(WSRequestHandler* req) * @category sources * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleGetSourceTypesList(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSourceTypesList(const RpcRequest& request) { OBSDataArrayAutoRelease idsArray = obs_data_array_create(); @@ -142,7 +142,7 @@ HandlerResponse WSRequestHandler::HandleGetSourceTypesList(WSRequestHandler* req OBSDataAutoRelease response = obs_data_create(); obs_data_set_array(response, "types", idsArray); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -159,20 +159,20 @@ HandlerResponse WSRequestHandler::HandleGetSourceTypesList(WSRequestHandler* req * @category sources * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleGetVolume(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetVolume(const RpcRequest& request) { - if (!req->hasField("source")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); if (sourceName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSDataAutoRelease response = obs_data_create(); @@ -180,7 +180,7 @@ HandlerResponse WSRequestHandler::HandleGetVolume(WSRequestHandler* req) obs_data_set_double(response, "volume", obs_source_get_volume(source)); obs_data_set_bool(response, "muted", obs_source_muted(source)); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -194,26 +194,26 @@ HandlerResponse WSRequestHandler::HandleGetVolume(WSRequestHandler* req) * @category sources * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleSetVolume(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetVolume(const RpcRequest& request) { - if (!req->hasField("source") || !req->hasField("volume")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source") || !request.hasField("volume")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); - float sourceVolume = obs_data_get_double(req->data, "volume"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); + float sourceVolume = obs_data_get_double(request.parameters(), "volume"); if (sourceName.isEmpty() || sourceVolume < 0.0 || sourceVolume > 1.0) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } obs_source_set_volume(source, sourceVolume); - return req->SendOKResponse(); + return request.success(); } /** @@ -229,27 +229,27 @@ HandlerResponse WSRequestHandler::HandleSetVolume(WSRequestHandler* req) * @category sources * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleGetMute(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetMute(const RpcRequest& request) { - if (!req->hasField("source")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); if (sourceName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSDataAutoRelease response = obs_data_create(); obs_data_set_string(response, "name", obs_source_get_name(source)); obs_data_set_bool(response, "muted", obs_source_muted(source)); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -263,26 +263,26 @@ HandlerResponse WSRequestHandler::HandleGetMute(WSRequestHandler* req) * @category sources * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleSetMute(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetMute(const RpcRequest& request) { - if (!req->hasField("source") || !req->hasField("mute")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source") || !request.hasField("mute")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); - bool mute = obs_data_get_bool(req->data, "mute"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); + bool mute = obs_data_get_bool(request.parameters(), "mute"); if (sourceName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } obs_source_set_muted(source, mute); - return req->SendOKResponse(); + return request.success(); } /** @@ -295,24 +295,24 @@ HandlerResponse WSRequestHandler::HandleSetMute(WSRequestHandler* req) * @category sources * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleToggleMute(WSRequestHandler* req) +RpcResponse WSRequestHandler::ToggleMute(const RpcRequest& request) { - if (!req->hasField("source")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); if (sourceName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } obs_source_set_muted(source, !obs_source_muted(source)); - return req->SendOKResponse(); + return request.success(); } /** @@ -326,26 +326,26 @@ HandlerResponse WSRequestHandler::HandleToggleMute(WSRequestHandler* req) * @category sources * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleSetSyncOffset(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetSyncOffset(const RpcRequest& request) { - if (!req->hasField("source") || !req->hasField("offset")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source") || !request.hasField("offset")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); - int64_t sourceSyncOffset = (int64_t)obs_data_get_int(req->data, "offset"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); + int64_t sourceSyncOffset = (int64_t)obs_data_get_int(request.parameters(), "offset"); if (sourceName.isEmpty() || sourceSyncOffset < 0) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } obs_source_set_sync_offset(source, sourceSyncOffset); - return req->SendOKResponse(); + return request.success(); } /** @@ -361,27 +361,27 @@ HandlerResponse WSRequestHandler::HandleSetSyncOffset(WSRequestHandler* req) * @category sources * @since 4.2.0 */ -HandlerResponse WSRequestHandler::HandleGetSyncOffset(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSyncOffset(const RpcRequest& request) { - if (!req->hasField("source")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source")) { + return request.failed("missing request parameters"); } - QString sourceName = obs_data_get_string(req->data, "source"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); if (sourceName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSDataAutoRelease response = obs_data_create(); obs_data_set_string(response, "name", obs_source_get_name(source)); obs_data_set_int(response, "offset", obs_source_get_sync_offset(source)); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -399,24 +399,24 @@ HandlerResponse WSRequestHandler::HandleGetSyncOffset(WSRequestHandler* req) * @category sources * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleGetSourceSettings(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSourceSettings(const RpcRequest& request) { - if (!req->hasField("sourceName")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } - if (req->hasField("sourceType")) { + if (request.hasField("sourceType")) { QString actualSourceType = obs_source_get_id(source); - QString requestedType = obs_data_get_string(req->data, "sourceType"); + QString requestedType = obs_data_get_string(request.parameters(), "sourceType"); if (actualSourceType != requestedType) { - return req->SendErrorResponse("specified source exists but is not of expected type"); + return request.failed("specified source exists but is not of expected type"); } } @@ -427,7 +427,7 @@ HandlerResponse WSRequestHandler::HandleGetSourceSettings(WSRequestHandler* req) obs_data_set_string(response, "sourceType", obs_source_get_id(source)); obs_data_set_obj(response, "sourceSettings", sourceSettings); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -446,29 +446,29 @@ HandlerResponse WSRequestHandler::HandleGetSourceSettings(WSRequestHandler* req) * @category sources * @since 4.3.0 */ -HandlerResponse WSRequestHandler::HandleSetSourceSettings(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetSourceSettings(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("sourceSettings")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("sourceSettings")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } - if (req->hasField("sourceType")) { + if (request.hasField("sourceType")) { QString actualSourceType = obs_source_get_id(source); - QString requestedType = obs_data_get_string(req->data, "sourceType"); + QString requestedType = obs_data_get_string(request.parameters(), "sourceType"); if (actualSourceType != requestedType) { - return req->SendErrorResponse("specified source exists but is not of expected type"); + return request.failed("specified source exists but is not of expected type"); } } OBSDataAutoRelease currentSettings = obs_source_get_settings(source); - OBSDataAutoRelease newSettings = obs_data_get_obj(req->data, "sourceSettings"); + OBSDataAutoRelease newSettings = obs_data_get_obj(request.parameters(), "sourceSettings"); OBSDataAutoRelease sourceSettings = obs_data_create(); obs_data_apply(sourceSettings, currentSettings); @@ -482,7 +482,7 @@ HandlerResponse WSRequestHandler::HandleSetSourceSettings(WSRequestHandler* req) obs_data_set_string(response, "sourceType", obs_source_get_id(source)); obs_data_set_obj(response, "sourceSettings", sourceSettings); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -524,27 +524,27 @@ HandlerResponse WSRequestHandler::HandleSetSourceSettings(WSRequestHandler* req) * @category sources * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetTextGDIPlusProperties(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetTextGDIPlusProperties(const RpcRequest& request) { - const char* sourceName = obs_data_get_string(req->data, "source"); + const char* sourceName = obs_data_get_string(request.parameters(), "source"); if (!sourceName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } QString sourceId = obs_source_get_id(source); if (sourceId != "text_gdiplus") { - return req->SendErrorResponse("not a text gdi plus source"); + return request.failed("not a text gdi plus source"); } OBSDataAutoRelease response = obs_source_get_settings(source); obs_data_set_string(response, "source", obs_source_get_name(source)); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -585,77 +585,77 @@ HandlerResponse WSRequestHandler::HandleGetTextGDIPlusProperties(WSRequestHandle * @category sources * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleSetTextGDIPlusProperties(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetTextGDIPlusProperties(const RpcRequest& request) { - if (!req->hasField("source")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "source"); + const char* sourceName = obs_data_get_string(request.parameters(), "source"); if (!sourceName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } QString sourceId = obs_source_get_id(source); if (sourceId != "text_gdiplus") { - return req->SendErrorResponse("not a text gdi plus source"); + return request.failed("not a text gdi plus source"); } OBSDataAutoRelease settings = obs_source_get_settings(source); - if (req->hasField("align")) { - obs_data_set_string(settings, "align", obs_data_get_string(req->data, "align")); + if (request.hasField("align")) { + obs_data_set_string(settings, "align", obs_data_get_string(request.parameters(), "align")); } - if (req->hasField("bk_color")) { - obs_data_set_int(settings, "bk_color", obs_data_get_int(req->data, "bk_color")); + if (request.hasField("bk_color")) { + obs_data_set_int(settings, "bk_color", obs_data_get_int(request.parameters(), "bk_color")); } - if (req->hasField("bk-opacity")) { - obs_data_set_int(settings, "bk_opacity", obs_data_get_int(req->data, "bk_opacity")); + if (request.hasField("bk-opacity")) { + obs_data_set_int(settings, "bk_opacity", obs_data_get_int(request.parameters(), "bk_opacity")); } - if (req->hasField("chatlog")) { - obs_data_set_bool(settings, "chatlog", obs_data_get_bool(req->data, "chatlog")); + if (request.hasField("chatlog")) { + obs_data_set_bool(settings, "chatlog", obs_data_get_bool(request.parameters(), "chatlog")); } - if (req->hasField("chatlog_lines")) { - obs_data_set_int(settings, "chatlog_lines", obs_data_get_int(req->data, "chatlog_lines")); + if (request.hasField("chatlog_lines")) { + obs_data_set_int(settings, "chatlog_lines", obs_data_get_int(request.parameters(), "chatlog_lines")); } - if (req->hasField("color")) { - obs_data_set_int(settings, "color", obs_data_get_int(req->data, "color")); + if (request.hasField("color")) { + obs_data_set_int(settings, "color", obs_data_get_int(request.parameters(), "color")); } - if (req->hasField("extents")) { - obs_data_set_bool(settings, "extents", obs_data_get_bool(req->data, "extents")); + if (request.hasField("extents")) { + obs_data_set_bool(settings, "extents", obs_data_get_bool(request.parameters(), "extents")); } - if (req->hasField("extents_wrap")) { - obs_data_set_bool(settings, "extents_wrap", obs_data_get_bool(req->data, "extents_wrap")); + if (request.hasField("extents_wrap")) { + obs_data_set_bool(settings, "extents_wrap", obs_data_get_bool(request.parameters(), "extents_wrap")); } - if (req->hasField("extents_cx")) { - obs_data_set_int(settings, "extents_cx", obs_data_get_int(req->data, "extents_cx")); + if (request.hasField("extents_cx")) { + obs_data_set_int(settings, "extents_cx", obs_data_get_int(request.parameters(), "extents_cx")); } - if (req->hasField("extents_cy")) { - obs_data_set_int(settings, "extents_cy", obs_data_get_int(req->data, "extents_cy")); + if (request.hasField("extents_cy")) { + obs_data_set_int(settings, "extents_cy", obs_data_get_int(request.parameters(), "extents_cy")); } - if (req->hasField("file")) { - obs_data_set_string(settings, "file", obs_data_get_string(req->data, "file")); + if (request.hasField("file")) { + obs_data_set_string(settings, "file", obs_data_get_string(request.parameters(), "file")); } - if (req->hasField("font")) { + if (request.hasField("font")) { OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); if (font_obj) { - OBSDataAutoRelease req_font_obj = obs_data_get_obj(req->data, "font"); + OBSDataAutoRelease req_font_obj = obs_data_get_obj(request.parameters(), "font"); if (obs_data_has_user_value(req_font_obj, "face")) { obs_data_set_string(font_obj, "face", obs_data_get_string(req_font_obj, "face")); @@ -675,57 +675,57 @@ HandlerResponse WSRequestHandler::HandleSetTextGDIPlusProperties(WSRequestHandle } } - if (req->hasField("gradient")) { - obs_data_set_bool(settings, "gradient", obs_data_get_bool(req->data, "gradient")); + if (request.hasField("gradient")) { + obs_data_set_bool(settings, "gradient", obs_data_get_bool(request.parameters(), "gradient")); } - if (req->hasField("gradient_color")) { - obs_data_set_int(settings, "gradient_color", obs_data_get_int(req->data, "gradient_color")); + if (request.hasField("gradient_color")) { + obs_data_set_int(settings, "gradient_color", obs_data_get_int(request.parameters(), "gradient_color")); } - if (req->hasField("gradient_dir")) { - obs_data_set_double(settings, "gradient_dir", obs_data_get_double(req->data, "gradient_dir")); + if (request.hasField("gradient_dir")) { + obs_data_set_double(settings, "gradient_dir", obs_data_get_double(request.parameters(), "gradient_dir")); } - if (req->hasField("gradient_opacity")) { - obs_data_set_int(settings, "gradient_opacity", obs_data_get_int(req->data, "gradient_opacity")); + if (request.hasField("gradient_opacity")) { + obs_data_set_int(settings, "gradient_opacity", obs_data_get_int(request.parameters(), "gradient_opacity")); } - if (req->hasField("outline")) { - obs_data_set_bool(settings, "outline", obs_data_get_bool(req->data, "outline")); + if (request.hasField("outline")) { + obs_data_set_bool(settings, "outline", obs_data_get_bool(request.parameters(), "outline")); } - if (req->hasField("outline_size")) { - obs_data_set_int(settings, "outline_size", obs_data_get_int(req->data, "outline_size")); + if (request.hasField("outline_size")) { + obs_data_set_int(settings, "outline_size", obs_data_get_int(request.parameters(), "outline_size")); } - if (req->hasField("outline_color")) { - obs_data_set_int(settings, "outline_color", obs_data_get_int(req->data, "outline_color")); + if (request.hasField("outline_color")) { + obs_data_set_int(settings, "outline_color", obs_data_get_int(request.parameters(), "outline_color")); } - if (req->hasField("outline_opacity")) { - obs_data_set_int(settings, "outline_opacity", obs_data_get_int(req->data, "outline_opacity")); + if (request.hasField("outline_opacity")) { + obs_data_set_int(settings, "outline_opacity", obs_data_get_int(request.parameters(), "outline_opacity")); } - if (req->hasField("read_from_file")) { - obs_data_set_bool(settings, "read_from_file", obs_data_get_bool(req->data, "read_from_file")); + if (request.hasField("read_from_file")) { + obs_data_set_bool(settings, "read_from_file", obs_data_get_bool(request.parameters(), "read_from_file")); } - if (req->hasField("text")) { - obs_data_set_string(settings, "text", obs_data_get_string(req->data, "text")); + if (request.hasField("text")) { + obs_data_set_string(settings, "text", obs_data_get_string(request.parameters(), "text")); } - if (req->hasField("valign")) { - obs_data_set_string(settings, "valign", obs_data_get_string(req->data, "valign")); + if (request.hasField("valign")) { + obs_data_set_string(settings, "valign", obs_data_get_string(request.parameters(), "valign")); } - if (req->hasField("vertical")) { - obs_data_set_bool(settings, "vertical", obs_data_get_bool(req->data, "vertical")); + if (request.hasField("vertical")) { + obs_data_set_bool(settings, "vertical", obs_data_get_bool(request.parameters(), "vertical")); } obs_source_update(source, settings); - return req->SendOKResponse(); + return request.success(); } /** @@ -755,27 +755,27 @@ HandlerResponse WSRequestHandler::HandleSetTextGDIPlusProperties(WSRequestHandle * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleGetTextFreetype2Properties(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetTextFreetype2Properties(const RpcRequest& request) { - const char* sourceName = obs_data_get_string(req->data, "source"); + const char* sourceName = obs_data_get_string(request.parameters(), "source"); if (!sourceName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } QString sourceId = obs_source_get_id(source); if (sourceId != "text_ft2_source") { - return req->SendErrorResponse("not a freetype 2 source"); + return request.failed("not a freetype 2 source"); } OBSDataAutoRelease response = obs_source_get_settings(source); obs_data_set_string(response, "source", sourceName); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -803,45 +803,45 @@ HandlerResponse WSRequestHandler::HandleGetTextFreetype2Properties(WSRequestHand * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleSetTextFreetype2Properties(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetTextFreetype2Properties(const RpcRequest& request) { - const char* sourceName = obs_data_get_string(req->data, "source"); + const char* sourceName = obs_data_get_string(request.parameters(), "source"); if (!sourceName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } QString sourceId = obs_source_get_id(source); if (sourceId != "text_ft2_source") { - return req->SendErrorResponse("not text freetype 2 source"); + return request.failed("not text freetype 2 source"); } OBSDataAutoRelease settings = obs_source_get_settings(source); - if (req->hasField("color1")) { - obs_data_set_int(settings, "color1", obs_data_get_int(req->data, "color1")); + if (request.hasField("color1")) { + obs_data_set_int(settings, "color1", obs_data_get_int(request.parameters(), "color1")); } - if (req->hasField("color2")) { - obs_data_set_int(settings, "color2", obs_data_get_int(req->data, "color2")); + if (request.hasField("color2")) { + obs_data_set_int(settings, "color2", obs_data_get_int(request.parameters(), "color2")); } - if (req->hasField("custom_width")) { - obs_data_set_int(settings, "custom_width", obs_data_get_int(req->data, "custom_width")); + if (request.hasField("custom_width")) { + obs_data_set_int(settings, "custom_width", obs_data_get_int(request.parameters(), "custom_width")); } - if (req->hasField("drop_shadow")) { - obs_data_set_bool(settings, "drop_shadow", obs_data_get_bool(req->data, "drop_shadow")); + if (request.hasField("drop_shadow")) { + obs_data_set_bool(settings, "drop_shadow", obs_data_get_bool(request.parameters(), "drop_shadow")); } - if (req->hasField("font")) { + if (request.hasField("font")) { OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); if (font_obj) { - OBSDataAutoRelease req_font_obj = obs_data_get_obj(req->data, "font"); + OBSDataAutoRelease req_font_obj = obs_data_get_obj(request.parameters(), "font"); if (obs_data_has_user_value(req_font_obj, "face")) { obs_data_set_string(font_obj, "face", obs_data_get_string(req_font_obj, "face")); @@ -861,33 +861,33 @@ HandlerResponse WSRequestHandler::HandleSetTextFreetype2Properties(WSRequestHand } } - if (req->hasField("from_file")) { - obs_data_set_bool(settings, "from_file", obs_data_get_bool(req->data, "from_file")); + if (request.hasField("from_file")) { + obs_data_set_bool(settings, "from_file", obs_data_get_bool(request.parameters(), "from_file")); } - if (req->hasField("log_mode")) { - obs_data_set_bool(settings, "log_mode", obs_data_get_bool(req->data, "log_mode")); + if (request.hasField("log_mode")) { + obs_data_set_bool(settings, "log_mode", obs_data_get_bool(request.parameters(), "log_mode")); } - if (req->hasField("outline")) { - obs_data_set_bool(settings, "outline", obs_data_get_bool(req->data, "outline")); + if (request.hasField("outline")) { + obs_data_set_bool(settings, "outline", obs_data_get_bool(request.parameters(), "outline")); } - if (req->hasField("text")) { - obs_data_set_string(settings, "text", obs_data_get_string(req->data, "text")); + if (request.hasField("text")) { + obs_data_set_string(settings, "text", obs_data_get_string(request.parameters(), "text")); } - if (req->hasField("text_file")) { - obs_data_set_string(settings, "text_file", obs_data_get_string(req->data, "text_file")); + if (request.hasField("text_file")) { + obs_data_set_string(settings, "text_file", obs_data_get_string(request.parameters(), "text_file")); } - if (req->hasField("word_wrap")) { - obs_data_set_bool(settings, "word_wrap", obs_data_get_bool(req->data, "word_wrap")); + if (request.hasField("word_wrap")) { + obs_data_set_bool(settings, "word_wrap", obs_data_get_bool(request.parameters(), "word_wrap")); } obs_source_update(source, settings); - return req->SendOKResponse(); + return request.success(); } /** @@ -910,27 +910,27 @@ HandlerResponse WSRequestHandler::HandleSetTextFreetype2Properties(WSRequestHand * @category sources * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetBrowserSourceProperties(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetBrowserSourceProperties(const RpcRequest& request) { - const char* sourceName = obs_data_get_string(req->data, "source"); + const char* sourceName = obs_data_get_string(request.parameters(), "source"); if (!sourceName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } QString sourceId = obs_source_get_id(source); if (sourceId != "browser_source" && sourceId != "linuxbrowser-source") { - return req->SendErrorResponse("not a browser source"); + return request.failed("not a browser source"); } OBSDataAutoRelease response = obs_source_get_settings(source); obs_data_set_string(response, "source", obs_source_get_name(source)); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -952,68 +952,68 @@ HandlerResponse WSRequestHandler::HandleGetBrowserSourceProperties(WSRequestHand * @category sources * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleSetBrowserSourceProperties(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetBrowserSourceProperties(const RpcRequest& request) { - if (!req->hasField("source")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("source")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "source"); + const char* sourceName = obs_data_get_string(request.parameters(), "source"); if (!sourceName) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } QString sourceId = obs_source_get_id(source); if(sourceId != "browser_source" && sourceId != "linuxbrowser-source") { - return req->SendErrorResponse("not a browser source"); + return request.failed("not a browser source"); } OBSDataAutoRelease settings = obs_source_get_settings(source); - if (req->hasField("restart_when_active")) { - obs_data_set_bool(settings, "restart_when_active", obs_data_get_bool(req->data, "restart_when_active")); + if (request.hasField("restart_when_active")) { + obs_data_set_bool(settings, "restart_when_active", obs_data_get_bool(request.parameters(), "restart_when_active")); } - if (req->hasField("shutdown")) { - obs_data_set_bool(settings, "shutdown", obs_data_get_bool(req->data, "shutdown")); + if (request.hasField("shutdown")) { + obs_data_set_bool(settings, "shutdown", obs_data_get_bool(request.parameters(), "shutdown")); } - if (req->hasField("is_local_file")) { - obs_data_set_bool(settings, "is_local_file", obs_data_get_bool(req->data, "is_local_file")); + if (request.hasField("is_local_file")) { + obs_data_set_bool(settings, "is_local_file", obs_data_get_bool(request.parameters(), "is_local_file")); } - if (req->hasField("local_file")) { - obs_data_set_string(settings, "local_file", obs_data_get_string(req->data, "local_file")); + if (request.hasField("local_file")) { + obs_data_set_string(settings, "local_file", obs_data_get_string(request.parameters(), "local_file")); } - if (req->hasField("url")) { - obs_data_set_string(settings, "url", obs_data_get_string(req->data, "url")); + if (request.hasField("url")) { + obs_data_set_string(settings, "url", obs_data_get_string(request.parameters(), "url")); } - if (req->hasField("css")) { - obs_data_set_string(settings, "css", obs_data_get_string(req->data, "css")); + if (request.hasField("css")) { + obs_data_set_string(settings, "css", obs_data_get_string(request.parameters(), "css")); } - if (req->hasField("width")) { - obs_data_set_int(settings, "width", obs_data_get_int(req->data, "width")); + if (request.hasField("width")) { + obs_data_set_int(settings, "width", obs_data_get_int(request.parameters(), "width")); } - if (req->hasField("height")) { - obs_data_set_int(settings, "height", obs_data_get_int(req->data, "height")); + if (request.hasField("height")) { + obs_data_set_int(settings, "height", obs_data_get_int(request.parameters(), "height")); } - if (req->hasField("fps")) { - obs_data_set_int(settings, "fps", obs_data_get_int(req->data, "fps")); + if (request.hasField("fps")) { + obs_data_set_int(settings, "fps", obs_data_get_int(request.parameters(), "fps")); } obs_source_update(source, settings); - return req->SendOKResponse(); + return request.success(); } /** @@ -1030,7 +1030,7 @@ HandlerResponse WSRequestHandler::HandleSetBrowserSourceProperties(WSRequestHand * @category sources * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetSpecialSources(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSpecialSources(const RpcRequest& request) { OBSDataAutoRelease response = obs_data_create(); @@ -1052,7 +1052,7 @@ HandlerResponse WSRequestHandler::HandleGetSpecialSources(WSRequestHandler* req) } } - return req->SendOKResponse(response); + return request.success(response); } /** @@ -1071,23 +1071,23 @@ HandlerResponse WSRequestHandler::HandleGetSpecialSources(WSRequestHandler* req) * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleGetSourceFilters(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSourceFilters(const RpcRequest& request) { - if (!req->hasField("sourceName")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSDataArrayAutoRelease filters = Utils::GetSourceFiltersList(source, true); OBSDataAutoRelease response = obs_data_create(); obs_data_set_array(response, "filters", filters); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -1106,26 +1106,26 @@ HandlerResponse WSRequestHandler::HandleGetSourceFilters(WSRequestHandler* req) * @category sources * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleGetSourceFilterInfo(WSRequestHandler* req) +RpcResponse WSRequestHandler::GetSourceFilterInfo(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("filterName")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } - const char* filterName = obs_data_get_string(req->data, "filterName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); OBSSourceAutoRelease filter = obs_source_get_filter_by_name(source, filterName); if (!filter) { - return req->SendErrorResponse("specified filter doesn't exist on specified source"); + return request.failed("specified filter doesn't exist on specified source"); } OBSDataAutoRelease response = Utils::GetSourceFilterInfo(filter, true); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -1141,40 +1141,40 @@ HandlerResponse WSRequestHandler::HandleGetSourceFilterInfo(WSRequestHandler* re * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleAddFilterToSource(WSRequestHandler* req) +RpcResponse WSRequestHandler::AddFilterToSource(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName") || - !req->hasField("filterType") || !req->hasField("filterSettings")) + if (!request.hasField("sourceName") || !request.hasField("filterName") || + !request.hasField("filterType") || !request.hasField("filterSettings")) { - return req->SendErrorResponse("missing request parameters"); + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); - const char* filterName = obs_data_get_string(req->data, "filterName"); - const char* filterType = obs_data_get_string(req->data, "filterType"); - OBSDataAutoRelease filterSettings = obs_data_get_obj(req->data, "filterSettings"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); + const char* filterType = obs_data_get_string(request.parameters(), "filterType"); + OBSDataAutoRelease filterSettings = obs_data_get_obj(request.parameters(), "filterSettings"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName); if (existingFilter) { - return req->SendErrorResponse("filter name already taken"); + return request.failed("filter name already taken"); } OBSSourceAutoRelease filter = obs_source_create_private(filterType, filterName, filterSettings); if (!filter) { - return req->SendErrorResponse("filter creation failed"); + return request.failed("filter creation failed"); } if (obs_source_get_type(filter) != OBS_SOURCE_TYPE_FILTER) { - return req->SendErrorResponse("invalid filter type"); + return request.failed("invalid filter type"); } obs_source_filter_add(source, filter); - return req->SendOKResponse(); + return request.success(); } /** @@ -1188,28 +1188,28 @@ HandlerResponse WSRequestHandler::HandleAddFilterToSource(WSRequestHandler* req) * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleRemoveFilterFromSource(WSRequestHandler* req) +RpcResponse WSRequestHandler::RemoveFilterFromSource(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("filterName")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); - const char* filterName = obs_data_get_string(req->data, "filterName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSSourceAutoRelease filter = obs_source_get_filter_by_name(source, filterName); if (!filter) { - return req->SendErrorResponse("specified filter doesn't exist"); + return request.failed("specified filter doesn't exist"); } obs_source_filter_remove(source, filter); - return req->SendOKResponse(); + return request.success(); } /** @@ -1224,28 +1224,28 @@ HandlerResponse WSRequestHandler::HandleRemoveFilterFromSource(WSRequestHandler* * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleReorderSourceFilter(WSRequestHandler* req) +RpcResponse WSRequestHandler::ReorderSourceFilter(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName") || !req->hasField("newIndex")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("filterName") || !request.hasField("newIndex")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); - const char* filterName = obs_data_get_string(req->data, "filterName"); - int newIndex = obs_data_get_int(req->data, "newIndex"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); + int newIndex = obs_data_get_int(request.parameters(), "newIndex"); if (newIndex < 0) { - return req->SendErrorResponse("invalid index"); + return request.failed("invalid index"); } OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSSourceAutoRelease filter = obs_source_get_filter_by_name(source, filterName); if (!filter) { - return req->SendErrorResponse("specified filter doesn't exist"); + return request.failed("specified filter doesn't exist"); } struct filterSearch { @@ -1265,7 +1265,7 @@ HandlerResponse WSRequestHandler::HandleReorderSourceFilter(WSRequestHandler* re int lastFilterIndex = ctx.i + 1; if (newIndex > lastFilterIndex) { - return req->SendErrorResponse("index out of bounds"); + return request.failed("index out of bounds"); } int currentIndex = ctx.filterIndex; @@ -1282,7 +1282,7 @@ HandlerResponse WSRequestHandler::HandleReorderSourceFilter(WSRequestHandler* re } } - return req->SendOKResponse(); + return request.success(); } /** @@ -1297,24 +1297,24 @@ HandlerResponse WSRequestHandler::HandleReorderSourceFilter(WSRequestHandler* re * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleMoveSourceFilter(WSRequestHandler* req) +RpcResponse WSRequestHandler::MoveSourceFilter(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName") || !req->hasField("movementType")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("filterName") || !request.hasField("movementType")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); - const char* filterName = obs_data_get_string(req->data, "filterName"); - QString movementType(obs_data_get_string(req->data, "movementType")); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); + QString movementType(obs_data_get_string(request.parameters(), "movementType")); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSSourceAutoRelease filter = obs_source_get_filter_by_name(source, filterName); if (!filter) { - return req->SendErrorResponse("specified filter doesn't exist"); + return request.failed("specified filter doesn't exist"); } obs_order_movement movement; @@ -1331,12 +1331,12 @@ HandlerResponse WSRequestHandler::HandleMoveSourceFilter(WSRequestHandler* req) movement = OBS_ORDER_MOVE_BOTTOM; } else { - return req->SendErrorResponse("invalid value for movementType: must be either 'up', 'down', 'top' or 'bottom'."); + return request.failed("invalid value for movementType: must be either 'up', 'down', 'top' or 'bottom'."); } obs_source_filter_set_order(source, filter, movement); - return req->SendOKResponse(); + return request.success(); } /** @@ -1351,31 +1351,31 @@ HandlerResponse WSRequestHandler::HandleMoveSourceFilter(WSRequestHandler* req) * @category sources * @since 4.5.0 */ -HandlerResponse WSRequestHandler::HandleSetSourceFilterSettings(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetSourceFilterSettings(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName") || !req->hasField("filterSettings")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("filterName") || !request.hasField("filterSettings")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); - const char* filterName = obs_data_get_string(req->data, "filterName"); - OBSDataAutoRelease newFilterSettings = obs_data_get_obj(req->data, "filterSettings"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); + OBSDataAutoRelease newFilterSettings = obs_data_get_obj(request.parameters(), "filterSettings"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } OBSSourceAutoRelease filter = obs_source_get_filter_by_name(source, filterName); if (!filter) { - return req->SendErrorResponse("specified filter doesn't exist"); + return request.failed("specified filter doesn't exist"); } OBSDataAutoRelease settings = obs_source_get_settings(filter); obs_data_apply(settings, newFilterSettings); obs_source_update(filter, settings); - return req->SendOKResponse(); + return request.success(); } /** @@ -1390,28 +1390,28 @@ HandlerResponse WSRequestHandler::HandleSetSourceFilterSettings(WSRequestHandler * @category sources * @since 4.7.0 */ -HandlerResponse WSRequestHandler::HandleSetSourceFilterVisibility(WSRequestHandler* req) +RpcResponse WSRequestHandler::SetSourceFilterVisibility(const RpcRequest& request) { - if (!req->hasField("sourceName") || !req->hasField("filterName") || !req->hasField("filterEnabled")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("sourceName") || !request.hasField("filterName") || !request.hasField("filterEnabled")) { + return request.failed("missing request parameters"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist"); + return request.failed("specified source doesn't exist"); } - const char* filterName = obs_data_get_string(req->data, "filterName"); + const char* filterName = obs_data_get_string(request.parameters(), "filterName"); OBSSourceAutoRelease filter = obs_source_get_filter_by_name(source, filterName); if (!filter) { - return req->SendErrorResponse("specified filter doesn't exist on specified source"); + return request.failed("specified filter doesn't exist on specified source"); } - bool filterEnabled = obs_data_get_bool(req->data, "filterEnabled"); + bool filterEnabled = obs_data_get_bool(request.parameters(), "filterEnabled"); obs_source_set_enabled(filter, filterEnabled); - return req->SendOKResponse(); + return request.success(); } /** @@ -1439,19 +1439,19 @@ HandlerResponse WSRequestHandler::HandleSetSourceFilterVisibility(WSRequestHandl * @category sources * @since 4.6.0 */ -HandlerResponse WSRequestHandler::HandleTakeSourceScreenshot(WSRequestHandler* req) { - if (!req->hasField("sourceName")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::TakeSourceScreenshot(const RpcRequest& request) { + if (!request.hasField("sourceName")) { + return request.failed("missing request parameters"); } - if (!req->hasField("embedPictureFormat") && !req->hasField("saveToFilePath")) { - return req->SendErrorResponse("At least 'embedPictureFormat' or 'saveToFilePath' must be specified"); + if (!request.hasField("embedPictureFormat") && !request.hasField("saveToFilePath")) { + return request.failed("At least 'embedPictureFormat' or 'saveToFilePath' must be specified"); } - const char* sourceName = obs_data_get_string(req->data, "sourceName"); + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); if (!source) { - return req->SendErrorResponse("specified source doesn't exist");; + return request.failed("specified source doesn't exist");; } const uint32_t sourceWidth = obs_source_get_base_width(source); @@ -1461,18 +1461,18 @@ HandlerResponse WSRequestHandler::HandleTakeSourceScreenshot(WSRequestHandler* r uint32_t imgWidth = sourceWidth; uint32_t imgHeight = sourceHeight; - if (req->hasField("width")) { - imgWidth = obs_data_get_int(req->data, "width"); + if (request.hasField("width")) { + imgWidth = obs_data_get_int(request.parameters(), "width"); - if (!req->hasField("height")) { + if (!request.hasField("height")) { imgHeight = ((double)imgWidth / sourceAspectRatio); } } - if (req->hasField("height")) { - imgHeight = obs_data_get_int(req->data, "height"); + if (request.hasField("height")) { + imgHeight = obs_data_get_int(request.parameters(), "height"); - if (!req->hasField("width")) { + if (!request.hasField("width")) { imgWidth = ((double)imgHeight * sourceAspectRatio); } } @@ -1524,25 +1524,25 @@ HandlerResponse WSRequestHandler::HandleTakeSourceScreenshot(WSRequestHandler* r obs_leave_graphics(); if (!renderSuccess) { - return req->SendErrorResponse("Source render failed"); + return request.failed("Source render failed"); } OBSDataAutoRelease response = obs_data_create(); - if (req->hasField("embedPictureFormat")) { - const char* pictureFormat = obs_data_get_string(req->data, "embedPictureFormat"); + if (request.hasField("embedPictureFormat")) { + const char* pictureFormat = obs_data_get_string(request.parameters(), "embedPictureFormat"); QByteArrayList supportedFormats = QImageWriter::supportedImageFormats(); if (!supportedFormats.contains(pictureFormat)) { QString errorMessage = QString("Unsupported picture format: %1").arg(pictureFormat); - return req->SendErrorResponse(errorMessage.toUtf8()); + return request.failed(errorMessage.toUtf8()); } QByteArray encodedImgBytes; QBuffer buffer(&encodedImgBytes); buffer.open(QBuffer::WriteOnly); if (!sourceImage.save(&buffer, pictureFormat)) { - return req->SendErrorResponse("Embed image encoding failed"); + return request.failed("Embed image encoding failed"); } buffer.close(); @@ -1554,17 +1554,17 @@ HandlerResponse WSRequestHandler::HandleTakeSourceScreenshot(WSRequestHandler* r obs_data_set_string(response, "img", imgBase64.toUtf8()); } - if (req->hasField("saveToFilePath")) { - QString filePathStr = obs_data_get_string(req->data, "saveToFilePath"); + if (request.hasField("saveToFilePath")) { + QString filePathStr = obs_data_get_string(request.parameters(), "saveToFilePath"); QFileInfo filePathInfo(filePathStr); QString absoluteFilePath = filePathInfo.absoluteFilePath(); if (!sourceImage.save(absoluteFilePath)) { - return req->SendErrorResponse("Image save failed"); + return request.failed("Image save failed"); } obs_data_set_string(response, "imageFile", absoluteFilePath.toUtf8()); } obs_data_set_string(response, "sourceName", obs_source_get_name(source)); - return req->SendOKResponse(response); + return request.success(response); } diff --git a/src/WSRequestHandler_Streaming.cpp b/src/WSRequestHandler_Streaming.cpp index 45bb5f44..4ee77d8b 100644 --- a/src/WSRequestHandler_Streaming.cpp +++ b/src/WSRequestHandler_Streaming.cpp @@ -20,7 +20,7 @@ * @category streaming * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetStreamingStatus(const RpcRequest& request) { auto events = GetEventsSystem(); OBSDataAutoRelease data = obs_data_create(); @@ -39,7 +39,7 @@ HandlerResponse WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req obs_data_set_string(data, "rec-timecode", recordingTimecode.toUtf8().constData()); } - return req->SendOKResponse(data); + return request.success(data); } /** @@ -50,11 +50,11 @@ HandlerResponse WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req * @category streaming * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleStartStopStreaming(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StartStopStreaming(const RpcRequest& request) { if (obs_frontend_streaming_active()) - return HandleStopStreaming(req); + return StopStreaming(request); else - return HandleStartStreaming(req); + return StartStreaming(request); } /** @@ -76,15 +76,15 @@ HandlerResponse WSRequestHandler::HandleStartStopStreaming(WSRequestHandler* req * @category streaming * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleStartStreaming(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StartStreaming(const RpcRequest& request) { if (obs_frontend_streaming_active() == false) { OBSService configuredService = obs_frontend_get_streaming_service(); OBSService newService = nullptr; // TODO: fix service memory leak - if (req->hasField("stream")) { - OBSDataAutoRelease streamData = obs_data_get_obj(req->data, "stream"); + if (request.hasField("stream")) { + OBSDataAutoRelease streamData = obs_data_get_obj(request.parameters(), "stream"); OBSDataAutoRelease newSettings = obs_data_get_obj(streamData, "settings"); OBSDataAutoRelease newMetadata = obs_data_get_obj(streamData, "metadata"); @@ -157,9 +157,9 @@ HandlerResponse WSRequestHandler::HandleStartStreaming(WSRequestHandler* req) { obs_frontend_set_streaming_service(configuredService); } - return req->SendOKResponse(); + return request.success(); } else { - return req->SendErrorResponse("streaming already active"); + return request.failed("streaming already active"); } } @@ -172,12 +172,12 @@ HandlerResponse WSRequestHandler::HandleStartStreaming(WSRequestHandler* req) { * @category streaming * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleStopStreaming(WSRequestHandler* req) { +RpcResponse WSRequestHandler::StopStreaming(const RpcRequest& request) { if (obs_frontend_streaming_active() == true) { obs_frontend_streaming_stop(); - return req->SendOKResponse(); + return request.success(); } else { - return req->SendErrorResponse("streaming not active"); + return request.failed("streaming not active"); } } @@ -198,16 +198,16 @@ HandlerResponse WSRequestHandler::HandleStopStreaming(WSRequestHandler* req) { * @category streaming * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleSetStreamSettings(WSRequestHandler* req) { +RpcResponse WSRequestHandler::SetStreamSettings(const RpcRequest& request) { OBSService service = obs_frontend_get_streaming_service(); - OBSDataAutoRelease requestSettings = obs_data_get_obj(req->data, "settings"); + OBSDataAutoRelease requestSettings = obs_data_get_obj(request.parameters(), "settings"); if (!requestSettings) { - return req->SendErrorResponse("'settings' are required'"); + return request.failed("'settings' are required'"); } QString serviceType = obs_service_get_type(service); - QString requestedType = obs_data_get_string(req->data, "type"); + QString requestedType = obs_data_get_string(request.parameters(), "type"); if (requestedType != nullptr && requestedType != serviceType) { OBSDataAutoRelease hotkeys = obs_hotkeys_save_service(service); @@ -231,7 +231,7 @@ HandlerResponse WSRequestHandler::HandleSetStreamSettings(WSRequestHandler* req) } //if save is specified we should immediately save the streaming service - if (obs_data_get_bool(req->data, "save")) { + if (obs_data_get_bool(request.parameters(), "save")) { obs_frontend_save_streaming_service(); } @@ -241,7 +241,7 @@ HandlerResponse WSRequestHandler::HandleSetStreamSettings(WSRequestHandler* req) obs_data_set_string(response, "type", requestedType.toUtf8()); obs_data_set_obj(response, "settings", serviceSettings); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -260,7 +260,7 @@ HandlerResponse WSRequestHandler::HandleSetStreamSettings(WSRequestHandler* req) * @category streaming * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetStreamSettings(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetStreamSettings(const RpcRequest& request) { OBSService service = obs_frontend_get_streaming_service(); const char* serviceType = obs_service_get_type(service); @@ -270,7 +270,7 @@ HandlerResponse WSRequestHandler::HandleGetStreamSettings(WSRequestHandler* req) obs_data_set_string(response, "type", serviceType); obs_data_set_obj(response, "settings", settings); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -281,9 +281,9 @@ HandlerResponse WSRequestHandler::HandleGetStreamSettings(WSRequestHandler* req) * @category streaming * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleSaveStreamSettings(WSRequestHandler* req) { +RpcResponse WSRequestHandler::SaveStreamSettings(const RpcRequest& request) { obs_frontend_save_streaming_service(); - return req->SendOKResponse(); + return request.success(); } @@ -299,19 +299,19 @@ HandlerResponse WSRequestHandler::HandleSaveStreamSettings(WSRequestHandler* req * @since 4.6.0 */ #if BUILD_CAPTIONS -HandlerResponse WSRequestHandler::HandleSendCaptions(WSRequestHandler* req) { - if (!req->hasField("text")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SendCaptions(const RpcRequest& request) { + if (!request.hasField("text")) { + return request.failed("missing request parameters"); } OBSOutputAutoRelease output = obs_frontend_get_streaming_output(); if (output) { - const char* caption = obs_data_get_string(req->data, "text"); + const char* caption = obs_data_get_string(request.parameters(), "text"); // Send caption text with immediately (0 second delay) obs_output_output_caption_text2(output, caption, 0.0); } - return req->SendOKResponse(); + return request.success(); } #endif diff --git a/src/WSRequestHandler_StudioMode.cpp b/src/WSRequestHandler_StudioMode.cpp index bfcdae4e..67928ee4 100644 --- a/src/WSRequestHandler_StudioMode.cpp +++ b/src/WSRequestHandler_StudioMode.cpp @@ -12,13 +12,13 @@ * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetStudioModeStatus(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetStudioModeStatus(const RpcRequest& request) { bool previewActive = obs_frontend_preview_program_mode_active(); OBSDataAutoRelease response = obs_data_create(); obs_data_set_bool(response, "studio-mode", previewActive); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -33,9 +33,9 @@ HandlerResponse WSRequestHandler::HandleGetStudioModeStatus(WSRequestHandler* re * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetPreviewScene(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetPreviewScene(const RpcRequest& request) { if (!obs_frontend_preview_program_mode_active()) { - return req->SendErrorResponse("studio mode not enabled"); + return request.failed("studio mode not enabled"); } OBSSourceAutoRelease scene = obs_frontend_get_current_preview_scene(); @@ -45,7 +45,7 @@ HandlerResponse WSRequestHandler::HandleGetPreviewScene(WSRequestHandler* req) { obs_data_set_string(data, "name", obs_source_get_name(scene)); obs_data_set_array(data, "sources", sceneItems); - return req->SendOKResponse(data); + return request.success(data); } /** @@ -59,23 +59,23 @@ HandlerResponse WSRequestHandler::HandleGetPreviewScene(WSRequestHandler* req) { * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleSetPreviewScene(WSRequestHandler* req) { +RpcResponse WSRequestHandler::SetPreviewScene(const RpcRequest& request) { if (!obs_frontend_preview_program_mode_active()) { - return req->SendErrorResponse("studio mode not enabled"); + return request.failed("studio mode not enabled"); } - if (!req->hasField("scene-name")) { - return req->SendErrorResponse("missing request parameters"); + if (!request.hasField("scene-name")) { + return request.failed("missing request parameters"); } - const char* scene_name = obs_data_get_string(req->data, "scene-name"); + const char* scene_name = obs_data_get_string(request.parameters(), "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(scene_name); if (!scene) { - return req->SendErrorResponse("specified scene doesn't exist"); + return request.failed("specified scene doesn't exist"); } obs_frontend_set_current_preview_scene(obs_scene_get_source(scene)); - return req->SendOKResponse(); + return request.success(); } /** @@ -91,25 +91,25 @@ HandlerResponse WSRequestHandler::HandleSetPreviewScene(WSRequestHandler* req) { * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleTransitionToProgram(WSRequestHandler* req) { +RpcResponse WSRequestHandler::TransitionToProgram(const RpcRequest& request) { if (!obs_frontend_preview_program_mode_active()) { - return req->SendErrorResponse("studio mode not enabled"); + return request.failed("studio mode not enabled"); } - if (req->hasField("with-transition")) { + if (request.hasField("with-transition")) { OBSDataAutoRelease transitionInfo = - obs_data_get_obj(req->data, "with-transition"); + obs_data_get_obj(request.parameters(), "with-transition"); if (obs_data_has_user_value(transitionInfo, "name")) { QString transitionName = obs_data_get_string(transitionInfo, "name"); if (transitionName.isEmpty()) { - return req->SendErrorResponse("invalid request parameters"); + return request.failed("invalid request parameters"); } bool success = Utils::SetTransitionByName(transitionName); if (!success) { - return req->SendErrorResponse("specified transition doesn't exist"); + return request.failed("specified transition doesn't exist"); } } @@ -121,7 +121,7 @@ HandlerResponse WSRequestHandler::HandleTransitionToProgram(WSRequestHandler* re } obs_frontend_preview_program_trigger_transition(); - return req->SendOKResponse(); + return request.success(); } /** @@ -132,9 +132,9 @@ HandlerResponse WSRequestHandler::HandleTransitionToProgram(WSRequestHandler* re * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleEnableStudioMode(WSRequestHandler* req) { +RpcResponse WSRequestHandler::EnableStudioMode(const RpcRequest& request) { obs_frontend_set_preview_program_mode(true); - return req->SendOKResponse(); + return request.success(); } /** @@ -145,9 +145,9 @@ HandlerResponse WSRequestHandler::HandleEnableStudioMode(WSRequestHandler* req) * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleDisableStudioMode(WSRequestHandler* req) { +RpcResponse WSRequestHandler::DisableStudioMode(const RpcRequest& request) { obs_frontend_set_preview_program_mode(false); - return req->SendOKResponse(); + return request.success(); } /** @@ -158,8 +158,8 @@ HandlerResponse WSRequestHandler::HandleDisableStudioMode(WSRequestHandler* req) * @category studio mode * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleToggleStudioMode(WSRequestHandler* req) { +RpcResponse WSRequestHandler::ToggleStudioMode(const RpcRequest& request) { bool previewProgramMode = obs_frontend_preview_program_mode_active(); obs_frontend_set_preview_program_mode(!previewProgramMode); - return req->SendOKResponse(); + return request.success(); } diff --git a/src/WSRequestHandler_Transitions.cpp b/src/WSRequestHandler_Transitions.cpp index 7295736b..7c22687c 100644 --- a/src/WSRequestHandler_Transitions.cpp +++ b/src/WSRequestHandler_Transitions.cpp @@ -14,7 +14,7 @@ * @category transitions * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetTransitionList(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetTransitionList(const RpcRequest& request) { OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition(); obs_frontend_source_list transitionList = {}; obs_frontend_get_transitions(&transitionList); @@ -34,7 +34,7 @@ HandlerResponse WSRequestHandler::HandleGetTransitionList(WSRequestHandler* req) obs_source_get_name(currentTransition)); obs_data_set_array(response, "transitions", transitions); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -48,7 +48,7 @@ HandlerResponse WSRequestHandler::HandleGetTransitionList(WSRequestHandler* req) * @category transitions * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetCurrentTransition(const RpcRequest& request) { OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition(); OBSDataAutoRelease response = obs_data_create(); @@ -58,7 +58,7 @@ HandlerResponse WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler* r if (!obs_transition_fixed(currentTransition)) obs_data_set_int(response, "duration", obs_frontend_get_transition_duration()); - return req->SendOKResponse(response); + return request.success(response); } /** @@ -71,18 +71,18 @@ HandlerResponse WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler* r * @category transitions * @since 0.3 */ -HandlerResponse WSRequestHandler::HandleSetCurrentTransition(WSRequestHandler* req) { - if (!req->hasField("transition-name")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetCurrentTransition(const RpcRequest& request) { + if (!request.hasField("transition-name")) { + return request.failed("missing request parameters"); } - QString name = obs_data_get_string(req->data, "transition-name"); + QString name = obs_data_get_string(request.parameters(), "transition-name"); bool success = Utils::SetTransitionByName(name); if (!success) { - return req->SendErrorResponse("requested transition does not exist"); + return request.failed("requested transition does not exist"); } - return req->SendOKResponse(); + return request.success(); } /** @@ -95,14 +95,14 @@ HandlerResponse WSRequestHandler::HandleSetCurrentTransition(WSRequestHandler* r * @category transitions * @since 4.0.0 */ -HandlerResponse WSRequestHandler::HandleSetTransitionDuration(WSRequestHandler* req) { - if (!req->hasField("duration")) { - return req->SendErrorResponse("missing request parameters"); +RpcResponse WSRequestHandler::SetTransitionDuration(const RpcRequest& request) { + if (!request.hasField("duration")) { + return request.failed("missing request parameters"); } - int ms = obs_data_get_int(req->data, "duration"); + int ms = obs_data_get_int(request.parameters(), "duration"); obs_frontend_set_transition_duration(ms); - return req->SendOKResponse(); + return request.success(); } /** @@ -115,8 +115,8 @@ HandlerResponse WSRequestHandler::HandleSetTransitionDuration(WSRequestHandler* * @category transitions * @since 4.1.0 */ -HandlerResponse WSRequestHandler::HandleGetTransitionDuration(WSRequestHandler* req) { +RpcResponse WSRequestHandler::GetTransitionDuration(const RpcRequest& request) { OBSDataAutoRelease response = obs_data_create(); obs_data_set_int(response, "transition-duration", obs_frontend_get_transition_duration()); - return req->SendOKResponse(response); + return request.success(response); } diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 1b062b97..c9f09362 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -31,6 +31,7 @@ with this program. If not, see #include "obs-websocket.h" #include "Config.h" #include "Utils.h" +#include "protocol/OBSRemoteProtocol.h" QT_USE_NAMESPACE @@ -124,8 +125,15 @@ void WSServer::stop() blog(LOG_INFO, "server stopped successfully"); } -void WSServer::broadcast(std::string message) +void WSServer::broadcast(const RpcEvent& event) { + OBSRemoteProtocol protocol; + std::string message = protocol.encodeEvent(event); + + if (GetConfig()->DebugEnabled) { + blog(LOG_INFO, "Update << '%s'", message.c_str()); + } + QMutexLocker locker(&_clMutex); for (connection_hdl hdl : _connections) { if (GetConfig()->AuthRequired) { @@ -171,8 +179,17 @@ void WSServer::onMessage(connection_hdl hdl, server::message_ptr message) ConnectionProperties& connProperties = _connectionProperties[hdl]; locker.unlock(); - WSRequestHandler handler(connProperties); - std::string response = handler.processIncomingMessage(payload); + if (GetConfig()->DebugEnabled) { + blog(LOG_INFO, "Request >> '%s'", payload.c_str()); + } + + WSRequestHandler requestHandler(connProperties); + OBSRemoteProtocol protocol; + std::string response = protocol.processMessage(requestHandler, payload); + + if (GetConfig()->DebugEnabled) { + blog(LOG_INFO, "Response << '%s'", response.c_str()); + } websocketpp::lib::error_code errorCode; _server.send(hdl, response, websocketpp::frame::opcode::text, errorCode); diff --git a/src/WSServer.h b/src/WSServer.h index 76e978e3..723f51af 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -30,8 +30,8 @@ with this program. If not, see #include #include "ConnectionProperties.h" - #include "WSRequestHandler.h" +#include "rpc/RpcEvent.h" using websocketpp::connection_hdl; @@ -46,7 +46,7 @@ public: virtual ~WSServer(); void start(quint16 port); void stop(); - void broadcast(std::string message); + void broadcast(const RpcEvent& event); QThreadPool* threadPool() { return &_threadPool; } diff --git a/src/protocol/OBSRemoteProtocol.cpp b/src/protocol/OBSRemoteProtocol.cpp new file mode 100644 index 00000000..e5b1da1a --- /dev/null +++ b/src/protocol/OBSRemoteProtocol.cpp @@ -0,0 +1,117 @@ +/* +obs-websocket +Copyright (C) 2016-2019 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#include + +#include "OBSRemoteProtocol.h" +#include "../WSRequestHandler.h" +#include "../rpc/RpcEvent.h" +#include "../Utils.h" + +std::string OBSRemoteProtocol::processMessage(WSRequestHandler& requestHandler, std::string message) +{ + std::string msgContainer(message); + const char* msg = msgContainer.c_str(); + + 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"); + } + + if (!obs_data_has_user_value(data, "request-type") || !obs_data_has_user_value(data, "message-id")) { + return errorResponse(QString::Null(), "missing request parameters"); + } + + QString methodName = obs_data_get_string(data, "request-type"); + QString messageId = obs_data_get_string(data, "message-id"); + + OBSDataAutoRelease params = obs_data_create(); + obs_data_apply(params, data); + obs_data_unset_user_value(params, "request-type"); + obs_data_unset_user_value(params, "message-id"); + + 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(); +} + +std::string OBSRemoteProtocol::encodeEvent(const RpcEvent& event) +{ + OBSDataAutoRelease eventData = obs_data_create(); + + QString updateType = event.updateType(); + obs_data_set_string(eventData, "update-type", updateType.toUtf8().constData()); + + if (obs_frontend_streaming_active()) { + QString streamingTimecode = Utils::nsToTimestamp(event.streamTime()); + obs_data_set_string(eventData, "stream-timecode", streamingTimecode.toUtf8().constData()); + } + + if (obs_frontend_recording_active()) { + QString recordingTimecode = Utils::nsToTimestamp(event.recordingTime()); + obs_data_set_string(eventData, "rec-timecode", recordingTimecode.toUtf8().constData()); + } + + OBSData additionalFields = event.additionalFields(); + if (additionalFields) { + obs_data_apply(eventData, additionalFields); + } + + return std::string(obs_data_get_json(eventData)); +} + +std::string OBSRemoteProtocol::buildResponse(QString messageId, QString status, obs_data_t* fields) +{ + OBSDataAutoRelease response = obs_data_create(); + if (!messageId.isNull()) { + obs_data_set_string(response, "message-id", messageId.toUtf8().constData()); + } + 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) +{ + return buildResponse(messageId, "ok", fields); +} + +std::string OBSRemoteProtocol::errorResponse(QString messageId, QString 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()); + return buildResponse(messageId, "error", fields); +} diff --git a/src/protocol/OBSRemoteProtocol.h b/src/protocol/OBSRemoteProtocol.h new file mode 100644 index 00000000..03d8aa7d --- /dev/null +++ b/src/protocol/OBSRemoteProtocol.h @@ -0,0 +1,38 @@ +/* +obs-websocket +Copyright (C) 2016-2019 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#pragma once + +#include +#include +#include + +class WSRequestHandler; +class RpcEvent; + +class OBSRemoteProtocol +{ +public: + std::string processMessage(WSRequestHandler& requestHandler, std::string message); + std::string encodeEvent(const RpcEvent& event); + +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); +}; diff --git a/src/rpc/RpcEvent.cpp b/src/rpc/RpcEvent.cpp new file mode 100644 index 00000000..a8d3b06b --- /dev/null +++ b/src/rpc/RpcEvent.cpp @@ -0,0 +1,35 @@ +/* +obs-websocket +Copyright (C) 2016-2020 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#include "RpcEvent.h" + +RpcEvent::RpcEvent( + const QString& updateType, + uint64_t streamTime, uint64_t recordingTime, + obs_data_t* additionalFields +) : + _updateType(updateType), + _streamTime(streamTime), + _recordingTime(recordingTime), + _additionalFields(nullptr) +{ + if (additionalFields) { + _additionalFields = obs_data_create(); + obs_data_apply(_additionalFields, additionalFields); + } +} \ No newline at end of file diff --git a/src/rpc/RpcEvent.h b/src/rpc/RpcEvent.h new file mode 100644 index 00000000..6dd0df99 --- /dev/null +++ b/src/rpc/RpcEvent.h @@ -0,0 +1,60 @@ +/* +obs-websocket +Copyright (C) 2016-2020 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#pragma once + +#include +#include + +#include "../obs-websocket.h" + +class RpcEvent +{ +public: + explicit RpcEvent( + const QString& updateType, + uint64_t streamTime, uint64_t recordingTime, + obs_data_t* additionalFields = nullptr + ); + + const QString& updateType() const + { + return _updateType; + } + + const uint64_t streamTime() const + { + return _streamTime; + } + + const uint64_t recordingTime() const + { + return _recordingTime; + } + + const OBSData additionalFields() const + { + return OBSData(_additionalFields); + } + +private: + QString _updateType; + uint64_t _streamTime; + uint64_t _recordingTime; + OBSDataAutoRelease _additionalFields; +}; diff --git a/src/rpc/RpcRequest.cpp b/src/rpc/RpcRequest.cpp new file mode 100644 index 00000000..04d62cb9 --- /dev/null +++ b/src/rpc/RpcRequest.cpp @@ -0,0 +1,104 @@ +/* +obs-websocket +Copyright (C) 2016-2019 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#include "RpcRequest.h" +#include "RpcResponse.h" + +RpcRequest::RpcRequest(const QString& messageId, const QString& methodName, obs_data_t* params) : + _messageId(messageId), + _methodName(methodName), + _parameters(nullptr) +{ + if (params) { + _parameters = obs_data_create(); + obs_data_apply(_parameters, params); + } +} + +const RpcResponse RpcRequest::success(obs_data_t* additionalFields) const +{ + return RpcResponse::ok(*this, additionalFields); +} + +const RpcResponse RpcRequest::failed(const QString& errorMessage, obs_data_t* additionalFields) const +{ + return RpcResponse::fail(*this, errorMessage, additionalFields); +} + +const bool RpcRequest::hasField(QString name, obs_data_type expectedFieldType, obs_data_number_type expectedNumberType) const +{ + if (!_parameters || name.isEmpty() || name.isNull()) { + return false; + } + + OBSDataItemAutoRelease dataItem = obs_data_item_byname(_parameters, name.toUtf8()); + if (!dataItem) { + return false; + } + + if (expectedFieldType != OBS_DATA_NULL) { + obs_data_type fieldType = obs_data_item_gettype(dataItem); + if (fieldType != expectedFieldType) { + return false; + } + + if (fieldType == OBS_DATA_NUMBER && expectedNumberType != OBS_DATA_NUM_INVALID) { + obs_data_number_type numberType = obs_data_item_numtype(dataItem); + if (numberType != expectedNumberType) { + return false; + } + } + } + + return true; +} + +const bool RpcRequest::hasBool(QString fieldName) const +{ + return this->hasField(fieldName, OBS_DATA_BOOLEAN); +} + +const bool RpcRequest::hasString(QString fieldName) const +{ + return this->hasField(fieldName, OBS_DATA_STRING); +} + +const bool RpcRequest::hasNumber(QString fieldName, obs_data_number_type expectedNumberType) const +{ + return this->hasField(fieldName, OBS_DATA_NUMBER, expectedNumberType); +} + +const bool RpcRequest::hasInteger(QString fieldName) const +{ + return this->hasNumber(fieldName, OBS_DATA_NUM_INT); +} + +const bool RpcRequest::hasDouble(QString fieldName) const +{ + return this->hasNumber(fieldName, OBS_DATA_NUM_DOUBLE); +} + +const bool RpcRequest::hasArray(QString fieldName) const +{ + return this->hasField(fieldName, OBS_DATA_ARRAY); +} + +const bool RpcRequest::hasObject(QString fieldName) const +{ + return this->hasField(fieldName, OBS_DATA_OBJECT); +} diff --git a/src/rpc/RpcRequest.h b/src/rpc/RpcRequest.h new file mode 100644 index 00000000..3e360150 --- /dev/null +++ b/src/rpc/RpcRequest.h @@ -0,0 +1,65 @@ +/* +obs-websocket +Copyright (C) 2016-2019 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#pragma once + +#include +#include +#include "../obs-websocket.h" + +// forward declarations +class RpcResponse; + +class RpcRequest +{ +public: + explicit RpcRequest(const QString& messageId, const QString& methodName, obs_data_t* params); + + const QString& messageId() const + { + return _messageId; + } + + const QString& methodName() const + { + return _methodName; + } + + const OBSData parameters() const + { + return OBSData(_parameters); + } + + const RpcResponse success(obs_data_t* additionalFields = nullptr) const; + const RpcResponse failed(const QString& errorMessage, obs_data_t* additionalFields = nullptr) const; + + const bool hasField(QString fieldName, obs_data_type expectedFieldType = OBS_DATA_NULL, + obs_data_number_type expectedNumberType = OBS_DATA_NUM_INVALID) const; + const bool hasBool(QString fieldName) const; + const bool hasString(QString fieldName) const; + const bool hasNumber(QString fieldName, obs_data_number_type expectedNumberType = OBS_DATA_NUM_INVALID) const; + const bool hasInteger(QString fieldName) const; + const bool hasDouble(QString fieldName) const; + const bool hasArray(QString fieldName) const; + const bool hasObject(QString fieldName) const; + +private: + const QString _messageId; + const QString _methodName; + OBSDataAutoRelease _parameters; +}; diff --git a/src/rpc/RpcResponse.cpp b/src/rpc/RpcResponse.cpp new file mode 100644 index 00000000..17f9f6e9 --- /dev/null +++ b/src/rpc/RpcResponse.cpp @@ -0,0 +1,48 @@ +/* +obs-websocket +Copyright (C) 2016-2019 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#include "RpcResponse.h" +#include "RpcRequest.h" + +RpcResponse::RpcResponse( + Status status, const QString& messageId, + const QString& methodName, obs_data_t* additionalFields +) : + _status(status), + _messageId(messageId), + _methodName(methodName), + _additionalFields(nullptr) +{ + if (additionalFields) { + _additionalFields = obs_data_create(); + obs_data_apply(_additionalFields, additionalFields); + } +} + +const RpcResponse RpcResponse::ok(const RpcRequest& request, obs_data_t* additionalFields) +{ + RpcResponse response(Status::Ok, request.messageId(), request.methodName(), additionalFields); + return response; +} + +const RpcResponse RpcResponse::fail(const RpcRequest& request, const QString& errorMessage, obs_data_t* additionalFields) +{ + RpcResponse response(Status::Error, request.messageId(), request.methodName(), additionalFields); + response._errorMessage = errorMessage; + return response; +} diff --git a/src/rpc/RpcResponse.h b/src/rpc/RpcResponse.h new file mode 100644 index 00000000..a6381bfd --- /dev/null +++ b/src/rpc/RpcResponse.h @@ -0,0 +1,70 @@ +/* +obs-websocket +Copyright (C) 2016-2019 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#pragma once + +#include +#include +#include "../obs-websocket.h" + +class RpcRequest; + +class RpcResponse +{ +public: + enum Status { Unknown, Ok, Error }; + + static RpcResponse ofRequest(const RpcRequest& request); + static const RpcResponse ok(const RpcRequest& request, obs_data_t* additionalFields = nullptr); + static const RpcResponse fail( + const RpcRequest& request, const QString& errorMessage, + obs_data_t* additionalFields = nullptr + ); + + Status status() { + return _status; + } + + const QString& messageId() const { + return _messageId; + } + + const QString& methodName() const { + return _methodName; + } + + const QString& errorMessage() const { + return _errorMessage; + } + + const OBSData additionalFields() const { + return OBSData(_additionalFields); + } + +private: + explicit RpcResponse( + Status status, + const QString& messageId, const QString& methodName, + obs_data_t* additionalFields = nullptr + ); + const Status _status; + const QString _messageId; + const QString _methodName; + QString _errorMessage; + OBSDataAutoRelease _additionalFields; +};