diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 2851e558..0a824379 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -436,8 +436,8 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} is {{condition}} {{value}}" AdvSceneSwitcher.condition.profile="Profile" AdvSceneSwitcher.condition.profile.entry="Current active profile is {{profiles}}" AdvSceneSwitcher.condition.websocket="Websocket" -AdvSceneSwitcher.condition.websocket.type.request="Request" -AdvSceneSwitcher.condition.websocket.type.event="Event" +AdvSceneSwitcher.condition.websocket.type.request="Scene Switcher Request" +AdvSceneSwitcher.condition.websocket.type.event="Scene Switcher Event" AdvSceneSwitcher.condition.websocket.useRegex="Use regular expressions" AdvSceneSwitcher.condition.websocket.entry.request="{{type}} was received:" AdvSceneSwitcher.condition.websocket.entry.event="{{type}} was received from {{connection}}:" @@ -664,10 +664,16 @@ AdvSceneSwitcher.action.sequence.status.none="none" AdvSceneSwitcher.action.sequence.restart="Restart from beginning once end of list is reached" AdvSceneSwitcher.action.sequence.continueFrom="Continue with selected item" AdvSceneSwitcher.action.websocket="Websocket" +AdvSceneSwitcher.action.websocket.api.sceneSwitcher="Scene Switcher message" +AdvSceneSwitcher.action.websocket.api.obsWebsocket="OBS websocket message" +AdvSceneSwitcher.action.websocket.api.genericWebsocket="Generic websocket message" AdvSceneSwitcher.action.websocket.type.request="Request" AdvSceneSwitcher.action.websocket.type.event="Event" -AdvSceneSwitcher.action.websocket.entry.request="Send scene switcher {{type}} via {{connection}}" -AdvSceneSwitcher.action.websocket.entry.event="Send scene switcher {{type}} to connected clients" +AdvSceneSwitcher.action.websocket.settingsConflictGeneric="Possible settings conflict: Generic websocket message selection with connection which follows the OBS protocol!" +AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websockte messages while message type requires OBS protocol!" +AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Send{{api}}of type{{type}}via{{connection}}" +AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Send{{api}}of type{{type}}to connected clients" +AdvSceneSwitcher.action.websocket.entry.generic="Send{{api}}via{{connection}}" AdvSceneSwitcher.action.http="Http" AdvSceneSwitcher.action.http.setHeaders="Set headers" AdvSceneSwitcher.action.http.headers="Headers:" diff --git a/src/macro-core/macro-action-websocket.cpp b/src/macro-core/macro-action-websocket.cpp index 206ce709..0f20573d 100644 --- a/src/macro-core/macro-action-websocket.cpp +++ b/src/macro-core/macro-action-websocket.cpp @@ -10,47 +10,75 @@ bool MacroActionWebsocket::_registered = MacroActionFactory::Register( {MacroActionWebsocket::Create, MacroActionWebsocketEdit::Create, "AdvSceneSwitcher.action.websocket"}); -const static std::map actionTypes = { - {MacroActionWebsocket::Type::REQUEST, - "AdvSceneSwitcher.action.websocket.type.request"}, - {MacroActionWebsocket::Type::EVENT, - "AdvSceneSwitcher.action.websocket.type.event"}, +const static std::map apiTypes = { + {MacroActionWebsocket::API::SCENE_SWITCHER, + "AdvSceneSwitcher.action.websocket.api.sceneSwitcher"}, + {MacroActionWebsocket::API::OBS_WEBSOCKET, + "AdvSceneSwitcher.action.websocket.api.obsWebsocket"}, + {MacroActionWebsocket::API::GENERIC_WEBSOCKET, + "AdvSceneSwitcher.action.websocket.api.genericWebsocket"}, }; -void MacroActionWebsocket::SendRequest() +const static std::map + messageTypes = { + {MacroActionWebsocket::MessageType::REQUEST, + "AdvSceneSwitcher.action.websocket.type.request"}, + {MacroActionWebsocket::MessageType::EVENT, + "AdvSceneSwitcher.action.websocket.type.event"}, +}; + +void MacroActionWebsocket::SendRequest(const std::string &msg) { auto connection = _connection.lock(); if (!connection) { return; } - connection->SendMsg(_message); + + connection->SendMsg(msg); } bool MacroActionWebsocket::PerformAction() { - switch (_type) { - case MacroActionWebsocket::Type::REQUEST: - SendRequest(); - break; - case MacroActionWebsocket::Type::EVENT: - SendWebsocketEvent(_message); - break; - default: - break; + if (_api != MacroActionWebsocket::API::SCENE_SWITCHER) { + SendRequest(_message); + return true; } + if (_type == MacroActionWebsocket::MessageType::REQUEST) { + auto vendorRequest = ConstructVendorRequestMessage(_message); + SendRequest(vendorRequest); + } else { + SendWebsocketEvent(_message); + } return true; } void MacroActionWebsocket::LogAction() const { + if (_api == API::GENERIC_WEBSOCKET) { + vblog(LOG_INFO, + "sent generic websocket message \"%s\" via \"%s\"", + _message.c_str(), + GetWeakConnectionName(_connection).c_str()); + return; + } + + if (_api == API::OBS_WEBSOCKET) { + vblog(LOG_INFO, "sent obs websocket message \"%s\" via \"%s\"", + _message.c_str(), + GetWeakConnectionName(_connection).c_str()); + return; + } + switch (_type) { - case MacroActionWebsocket::Type::REQUEST: - vblog(LOG_INFO, "sent msg \"%s\" via \"%s\"", _message.c_str(), + case MacroActionWebsocket::MessageType::REQUEST: + vblog(LOG_INFO, "sent scene switcher message \"%s\" via \"%s\"", + _message.c_str(), GetWeakConnectionName(_connection).c_str()); break; - case MacroActionWebsocket::Type::EVENT: - vblog(LOG_INFO, "sent event \"%s\" to connected clients", + case MacroActionWebsocket::MessageType::EVENT: + vblog(LOG_INFO, + "sent scene switcher event \"%s\" to connected clients", _message.c_str()); break; default: @@ -61,6 +89,7 @@ void MacroActionWebsocket::LogAction() const bool MacroActionWebsocket::Save(obs_data_t *obj) const { MacroAction::Save(obj); + obs_data_set_int(obj, "api", static_cast(_api)); obs_data_set_int(obj, "type", static_cast(_type)); _message.Save(obj, "message"); obs_data_set_string(obj, "connection", @@ -71,7 +100,8 @@ bool MacroActionWebsocket::Save(obs_data_t *obj) const bool MacroActionWebsocket::Load(obs_data_t *obj) { MacroAction::Load(obj); - _type = static_cast(obs_data_get_int(obj, "type")); + _api = static_cast(obs_data_get_int(obj, "api")); + _type = static_cast(obs_data_get_int(obj, "type")); _message.Load(obj, "message"); _connection = GetWeakConnectionByName(obs_data_get_string(obj, "connection")); @@ -80,40 +110,54 @@ bool MacroActionWebsocket::Load(obs_data_t *obj) std::string MacroActionWebsocket::GetShortDesc() const { - if (_type == Type::REQUEST) { + if (_type == MessageType::REQUEST) { return GetWeakConnectionName(_connection); } return ""; } -static inline void populateActionSelection(QComboBox *list) +static inline void populateAPISelection(QComboBox *list) { - for (auto entry : actionTypes) { - list->addItem(obs_module_text(entry.second.c_str())); + for (const auto &[_, name] : apiTypes) { + list->addItem(obs_module_text(name.c_str())); + } +} + +static inline void populateMessageTypeSelection(QComboBox *list) +{ + for (const auto &[_, name] : messageTypes) { + list->addItem(obs_module_text(name.c_str())); } } MacroActionWebsocketEdit::MacroActionWebsocketEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), - _actions(new QComboBox(this)), + _apiType(new QComboBox(this)), + _messageType(new QComboBox(this)), _message(new VariableTextEdit(this)), _connection(new ConnectionSelection(this)), - _editLayout(new QHBoxLayout()) + _editLayout(new QHBoxLayout()), + _settingsConflict(new QLabel()) { - populateActionSelection(_actions); + populateAPISelection(_apiType); + populateMessageTypeSelection(_messageType); + _settingsConflict->setWordWrap(true); - QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, - SLOT(ActionChanged(int))); + QWidget::connect(_apiType, SIGNAL(currentIndexChanged(int)), this, + SLOT(APITypeChanged(int))); + QWidget::connect(_messageType, SIGNAL(currentIndexChanged(int)), this, + SLOT(MessageTypeChanged(int))); QWidget::connect(_message, SIGNAL(textChanged()), this, SLOT(MessageChanged())); QWidget::connect(_connection, SIGNAL(SelectionChanged(const QString &)), this, SLOT(ConnectionSelectionChanged(const QString &))); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto mainLayout = new QVBoxLayout; mainLayout->addLayout(_editLayout); mainLayout->addWidget(_message); + mainLayout->addWidget(_settingsConflict); setLayout(mainLayout); _entryData = entryData; @@ -121,34 +165,111 @@ MacroActionWebsocketEdit::MacroActionWebsocketEdit( _loading = false; } +void MacroActionWebsocketEdit::CheckForSettingsConflict() +{ + auto connection = _entryData->_connection.lock(); + if (!connection) { + _settingsConflict->hide(); + return; + } + + if (_entryData->_api == MacroActionWebsocket::API::GENERIC_WEBSOCKET && + connection->IsUsingOBSProtocol()) { + _settingsConflict->show(); + _settingsConflict->setText(obs_module_text( + "AdvSceneSwitcher.action.websocket.settingsConflictGeneric")); + } else if (_entryData->_api != + MacroActionWebsocket::API::GENERIC_WEBSOCKET && + !connection->IsUsingOBSProtocol()) { + _settingsConflict->show(); + _settingsConflict->setText(obs_module_text( + "AdvSceneSwitcher.action.websocket.settingsConflictOBS")); + } else { + _settingsConflict->hide(); + } + + adjustSize(); + updateGeometry(); +} + +void MacroActionWebsocketEdit::SetupWidgetVisibility() +{ + _messageType->setVisible(_entryData->_api == + MacroActionWebsocket::API::SCENE_SWITCHER); + switch (_entryData->_api) { + case MacroActionWebsocket::API::SCENE_SWITCHER: + if (_entryData->_type == + MacroActionWebsocket::MessageType::REQUEST) { + SetupRequestEdit(); + } else { + SetupEventEdit(); + } + break; + case MacroActionWebsocket::API::OBS_WEBSOCKET: + case MacroActionWebsocket::API::GENERIC_WEBSOCKET: + SetupGenericEdit(); + break; + default: + break; + } + + CheckForSettingsConflict(); + + adjustSize(); + updateGeometry(); +} + void MacroActionWebsocketEdit::SetupRequestEdit() { - _editLayout->removeWidget(_actions); - _editLayout->removeWidget(_connection); - ClearLayout(_editLayout); - std::unordered_map widgetPlaceholders = { - {"{{type}}", _actions}, - {"{{connection}}", _connection}, - }; - PlaceWidgets(obs_module_text( - "AdvSceneSwitcher.action.websocket.entry.request"), - _editLayout, widgetPlaceholders); + ClearWidgets(); + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request"), + _editLayout, + {{"{{api}}", _apiType}, + {"{{type}}", _messageType}, + {"{{connection}}", _connection}}); _connection->show(); } void MacroActionWebsocketEdit::SetupEventEdit() { - _editLayout->removeWidget(_actions); + ClearWidgets(); + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event"), + _editLayout, + {{"{{api}}", _apiType}, + {"{{type}}", _messageType}, + {"{{connection}}", _connection}}); + + // Add widget to layout but hide it + _editLayout->addWidget(_connection); + _connection->hide(); +} + +void MacroActionWebsocketEdit::SetupGenericEdit() +{ + ClearWidgets(); + PlaceWidgets(obs_module_text( + "AdvSceneSwitcher.action.websocket.entry.generic"), + _editLayout, + {{"{{api}}", _apiType}, + {"{{type}}", _messageType}, + {"{{connection}}", _connection}}); + _connection->show(); + + // Add widget to layout but hide it + _editLayout->addWidget(_messageType); + _messageType->hide(); +} + +void MacroActionWebsocketEdit::ClearWidgets() +{ + _editLayout->removeWidget(_apiType); + _editLayout->removeWidget(_messageType); _editLayout->removeWidget(_connection); ClearLayout(_editLayout); - std::unordered_map widgetPlaceholders = { - {"{{type}}", _actions}, - {"{{connection}}", _connection}, - }; - PlaceWidgets(obs_module_text( - "AdvSceneSwitcher.action.websocket.entry.event"), - _editLayout, widgetPlaceholders); - _connection->hide(); } void MacroActionWebsocketEdit::UpdateEntryData() @@ -157,33 +278,37 @@ void MacroActionWebsocketEdit::UpdateEntryData() return; } - _actions->setCurrentIndex(static_cast(_entryData->_type)); + _apiType->setCurrentIndex(static_cast(_entryData->_api)); + _messageType->setCurrentIndex(static_cast(_entryData->_type)); _message->setPlainText(_entryData->_message); _connection->SetConnection(_entryData->_connection); - if (_entryData->_type == MacroActionWebsocket::Type::REQUEST) { - SetupRequestEdit(); - } else { - SetupEventEdit(); - } - - adjustSize(); - updateGeometry(); + SetupWidgetVisibility(); } -void MacroActionWebsocketEdit::ActionChanged(int index) +void MacroActionWebsocketEdit::APITypeChanged(int index) { if (_loading || !_entryData) { return; } auto lock = LockContext(); - _entryData->_type = static_cast(index); - if (_entryData->_type == MacroActionWebsocket::Type::REQUEST) { - SetupRequestEdit(); - } else { - SetupEventEdit(); + _entryData->_api = static_cast(index); + SetupWidgetVisibility(); + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); +} + +void MacroActionWebsocketEdit::MessageTypeChanged(int index) +{ + if (_loading || !_entryData) { + return; } + + auto lock = LockContext(); + _entryData->_type = + static_cast(index); + SetupWidgetVisibility(); emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } @@ -210,6 +335,7 @@ void MacroActionWebsocketEdit::ConnectionSelectionChanged( auto lock = LockContext(); _entryData->_connection = GetWeakConnectionByQString(connection); + CheckForSettingsConflict(); emit(HeaderInfoChanged(connection)); } diff --git a/src/macro-core/macro-action-websocket.hpp b/src/macro-core/macro-action-websocket.hpp index 0b134d10..769bfc3c 100644 --- a/src/macro-core/macro-action-websocket.hpp +++ b/src/macro-core/macro-action-websocket.hpp @@ -24,17 +24,24 @@ public: return std::make_shared(m); } - enum class Type { + enum class API { + SCENE_SWITCHER, + OBS_WEBSOCKET, + GENERIC_WEBSOCKET, + }; + + enum class MessageType { REQUEST, EVENT, }; - Type _type = Type::REQUEST; + API _api = API::SCENE_SWITCHER; + MessageType _type = MessageType::REQUEST; StringVariable _message = obs_module_text("AdvSceneSwitcher.enterText"); std::weak_ptr _connection; private: - void SendRequest(); + void SendRequest(const std::string &msg); static bool _registered; static const std::string id; @@ -57,7 +64,8 @@ public: } private slots: - void ActionChanged(int); + void APITypeChanged(int); + void MessageTypeChanged(int); void MessageChanged(); void ConnectionSelectionChanged(const QString &); signals: @@ -67,13 +75,20 @@ protected: std::shared_ptr _entryData; private: + void CheckForSettingsConflict(); + void SetupWidgetVisibility(); void SetupRequestEdit(); void SetupEventEdit(); + void SetupGenericEdit(); + void ClearWidgets(); - QComboBox *_actions; + QComboBox *_apiType; + QComboBox *_messageType; VariableTextEdit *_message; ConnectionSelection *_connection; QHBoxLayout *_editLayout; + QLabel *_settingsConflict; + bool _loading = true; }; diff --git a/src/utils/connection-manager.cpp b/src/utils/connection-manager.cpp index 0522b465..d4f8faa7 100644 --- a/src/utils/connection-manager.cpp +++ b/src/utils/connection-manager.cpp @@ -131,6 +131,7 @@ Connection *GetConnectionByName(const QString &name) { return GetConnectionByName(name.toStdString()); } + Connection *GetConnectionByName(const std::string &name) { for (auto &con : switcher->connections) { diff --git a/src/utils/connection-manager.hpp b/src/utils/connection-manager.hpp index 0177d9a7..2d6d6f51 100644 --- a/src/utils/connection-manager.hpp +++ b/src/utils/connection-manager.hpp @@ -40,6 +40,7 @@ public: void Save(obs_data_t *obj) const; std::string GetName() { return _name; } std::vector &Events() { return _client.Events(); } + bool IsUsingOBSProtocol() { return _useOBSWSProtocol; } private: void UseOBSWebsocketProtocol(bool); diff --git a/src/utils/websocket-helpers.cpp b/src/utils/websocket-helpers.cpp index 9fe5aed0..530dcbe2 100644 --- a/src/utils/websocket-helpers.cpp +++ b/src/utils/websocket-helpers.cpp @@ -75,8 +75,7 @@ extern "C" void RegisterWebsocketVendor() } } -WSConnection::WSConnection(bool useOBSProtocol) - : QObject(nullptr), _useOBSProtocol(useOBSProtocol) +WSConnection::WSConnection(bool useOBSProtocol) : QObject(nullptr) { _client.get_alog().clear_channels( websocketpp::log::alevel::frame_header | @@ -179,14 +178,13 @@ void WSConnection::Disconnect() _status = Status::DISCONNECTED; } -static std::string constructVendorRequestMessage(const std::string &message, - const std::string &uri) +std::string ConstructVendorRequestMessage(const std::string &message) { auto request = obs_data_create(); obs_data_set_int(request, "op", 6); auto *data = obs_data_create(); obs_data_set_string(data, "requestType", "CallVendorRequest"); - obs_data_set_string(data, "requestId", (message + " - " + uri).c_str()); + obs_data_set_string(data, "requestId", message.c_str()); auto vendorData = obs_data_create(); obs_data_set_string(vendorData, "vendorName", VendorName); @@ -211,11 +209,7 @@ static std::string constructVendorRequestMessage(const std::string &message, void WSConnection::SendRequest(const std::string &msg) { - if (_useOBSProtocol) { - Send(constructVendorRequestMessage(msg, _uri)); - } else { - Send(msg); - } + Send(msg); } WSConnection::Status WSConnection::GetStatus() const @@ -225,7 +219,6 @@ WSConnection::Status WSConnection::GetStatus() const void WSConnection::UseOBSWebsocketProtocol(bool useOBSProtocol) { - _useOBSProtocol = useOBSProtocol; _client.set_open_handler(bind(useOBSProtocol ? &WSConnection::OnOBSOpen : &WSConnection::OnGenericOpen, diff --git a/src/utils/websocket-helpers.hpp b/src/utils/websocket-helpers.hpp index 145d9098..e807ef43 100644 --- a/src/utils/websocket-helpers.hpp +++ b/src/utils/websocket-helpers.hpp @@ -30,6 +30,7 @@ constexpr char VendorEvent[] = "AdvancedSceneSwitcherEvent"; void ClearWebsocketMessages(); void SendWebsocketEvent(const std::string &); +std::string ConstructVendorRequestMessage(const std::string &message); class WSConnection : public QObject { public: @@ -79,7 +80,6 @@ private: std::atomic_bool _disconnect{false}; std::vector _messages; - bool _useOBSProtocol = true; }; } // namespace advss