diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini
index 0d9ece06..0b69c742 100644
--- a/data/locale/en-US.ini
+++ b/data/locale/en-US.ini
@@ -12,3 +12,6 @@ OBSWebsocket.NotifyDisconnect.Title="WebSocket client disconnected"
OBSWebsocket.NotifyDisconnect.Message="Client %1 disconnected"
OBSWebsocket.Server.StartFailed.Title="WebSocket Server failure"
OBSWebsocket.Server.StartFailed.Message="The obs-websocket server failed to start, maybe because:\n - TCP port %1 may currently be in use elsewhere on this system, possibly by another application. Try setting a different TCP port in the WebSocket server settings, or stop any application that could be using this port.\n - An unknown network error happened on your system. Try again by changing settings, restarting OBS or restarting your system."
+OBSWebsocket.ProfileChanged.Started="WebSockets server enabled in this profile. Server started."
+OBSWebsocket.ProfileChanged.Stopped="WebSockets server disabled in this profile. Server stopped."
+OBSWebsocket.ProfileChanged.Restarted="WebSockets server port changed in this profile. Server restarted."
\ No newline at end of file
diff --git a/src/Config.cpp b/src/Config.cpp
index a3746838..9ff7a653 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -17,10 +17,10 @@ with this program. If not, see
*/
#include
-#include
#include
#include
+#include
#define SECTION_NAME "WebsocketAPI"
#define PARAM_ENABLE "ServerEnabled"
@@ -31,8 +31,10 @@ with this program. If not, see
#define PARAM_SECRET "AuthSecret"
#define PARAM_SALT "AuthSalt"
-#include "Config.h"
#include "Utils.h"
+#include "WSServer.h"
+
+#include "Config.h"
#define QT_TO_UTF8(str) str.toUtf8().constData()
@@ -55,8 +57,55 @@ Config::Config() :
{
qsrand(QTime::currentTime().msec());
+ SetDefaults();
+ SessionChallenge = GenerateSalt();
+
+ obs_frontend_add_event_callback(OnFrontendEvent, this);
+}
+
+Config::~Config()
+{
+ obs_frontend_remove_event_callback(OnFrontendEvent, this);
+}
+
+void Config::Load()
+{
+ config_t* obsConfig = GetConfigStore();
+
+ ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE);
+ ServerPort = config_get_uint(obsConfig, SECTION_NAME, PARAM_PORT);
+
+ DebugEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_DEBUG);
+ AlertsEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ALERT);
+
+ AuthRequired = config_get_bool(obsConfig, SECTION_NAME, PARAM_AUTHREQUIRED);
+ Secret = config_get_string(obsConfig, SECTION_NAME, PARAM_SECRET);
+ Salt = config_get_string(obsConfig, SECTION_NAME, PARAM_SALT);
+}
+
+void Config::Save()
+{
+ config_t* obsConfig = GetConfigStore();
+
+ config_set_bool(obsConfig, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
+ config_set_uint(obsConfig, SECTION_NAME, PARAM_PORT, ServerPort);
+
+ config_set_bool(obsConfig, SECTION_NAME, PARAM_DEBUG, DebugEnabled);
+ config_set_bool(obsConfig, SECTION_NAME, PARAM_ALERT, AlertsEnabled);
+
+ config_set_bool(obsConfig, SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
+ config_set_string(obsConfig, SECTION_NAME, PARAM_SECRET,
+ QT_TO_UTF8(Secret));
+ config_set_string(obsConfig, SECTION_NAME, PARAM_SALT,
+ QT_TO_UTF8(Salt));
+
+ config_save(obsConfig);
+}
+
+void Config::SetDefaults()
+{
// OBS Config defaults
- config_t* obsConfig = obs_frontend_get_global_config();
+ config_t* obsConfig = GetConfigStore();
if (obsConfig) {
config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_ENABLE, ServerEnabled);
@@ -75,46 +124,11 @@ Config::Config() :
config_set_default_string(obsConfig,
SECTION_NAME, PARAM_SALT, QT_TO_UTF8(Salt));
}
-
- SessionChallenge = GenerateSalt();
}
-Config::~Config()
+config_t* Config::GetConfigStore()
{
-}
-
-void Config::Load()
-{
- config_t* obsConfig = obs_frontend_get_global_config();
-
- ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE);
- ServerPort = config_get_uint(obsConfig, SECTION_NAME, PARAM_PORT);
-
- DebugEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_DEBUG);
- AlertsEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ALERT);
-
- AuthRequired = config_get_bool(obsConfig, SECTION_NAME, PARAM_AUTHREQUIRED);
- Secret = config_get_string(obsConfig, SECTION_NAME, PARAM_SECRET);
- Salt = config_get_string(obsConfig, SECTION_NAME, PARAM_SALT);
-}
-
-void Config::Save()
-{
- config_t* obsConfig = obs_frontend_get_global_config();
-
- config_set_bool(obsConfig, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
- config_set_uint(obsConfig, SECTION_NAME, PARAM_PORT, ServerPort);
-
- config_set_bool(obsConfig, SECTION_NAME, PARAM_DEBUG, DebugEnabled);
- config_set_bool(obsConfig, SECTION_NAME, PARAM_ALERT, AlertsEnabled);
-
- config_set_bool(obsConfig, SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
- config_set_string(obsConfig, SECTION_NAME, PARAM_SECRET,
- QT_TO_UTF8(Secret));
- config_set_string(obsConfig, SECTION_NAME, PARAM_SALT,
- QT_TO_UTF8(Salt));
-
- config_save(obsConfig);
+ return obs_frontend_get_profile_config();
}
QString Config::GenerateSalt()
@@ -184,3 +198,96 @@ bool Config::CheckAuth(QString response)
return authSuccess;
}
+
+void Config::OnFrontendEvent(enum obs_frontend_event event, void* param)
+{
+ auto config = reinterpret_cast(param);
+
+ if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED) {
+ obs_frontend_push_ui_translation(obs_module_get_string);
+ QString startMessage = QObject::tr("OBSWebsocket.ProfileChanged.Started");
+ QString stopMessage = QObject::tr("OBSWebsocket.ProfileChanged.Stopped");
+ QString restartMessage = QObject::tr("OBSWebsocket.ProfileChanged.Restarted");
+ obs_frontend_pop_ui_translation();
+
+ bool previousEnabled = config->ServerEnabled;
+ uint64_t previousPort = config->ServerPort;
+
+ config->SetDefaults();
+ config->Load();
+
+ if (config->ServerEnabled != previousEnabled || config->ServerPort != previousPort) {
+ auto server = WSServer::Current();
+ server->stop();
+
+ if (config->ServerEnabled) {
+ server->start(config->ServerPort);
+
+ if (previousEnabled != config->ServerEnabled) {
+ Utils::SysTrayNotify(startMessage, QSystemTrayIcon::MessageIcon::Information);
+ } else {
+ Utils::SysTrayNotify(restartMessage, QSystemTrayIcon::MessageIcon::Information);
+ }
+ } else {
+ Utils::SysTrayNotify(stopMessage, QSystemTrayIcon::MessageIcon::Information);
+ }
+ }
+ }
+}
+
+void Config::MigrateFromGlobalSettings()
+{
+ config_t* source = obs_frontend_get_global_config();
+ config_t* destination = obs_frontend_get_profile_config();
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_ENABLE)) {
+ bool value = config_get_bool(source, SECTION_NAME, PARAM_ENABLE);
+ config_set_bool(destination, SECTION_NAME, PARAM_ENABLE, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_ENABLE);
+ }
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_PORT)) {
+ uint64_t value = config_get_uint(source, SECTION_NAME, PARAM_PORT);
+ config_set_uint(destination, SECTION_NAME, PARAM_PORT, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_PORT);
+ }
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_DEBUG)) {
+ bool value = config_get_bool(source, SECTION_NAME, PARAM_DEBUG);
+ config_set_bool(destination, SECTION_NAME, PARAM_DEBUG, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_DEBUG);
+ }
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_ALERT)) {
+ bool value = config_get_bool(source, SECTION_NAME, PARAM_ALERT);
+ config_set_bool(destination, SECTION_NAME, PARAM_ALERT, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_ALERT);
+ }
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_AUTHREQUIRED)) {
+ bool value = config_get_bool(source, SECTION_NAME, PARAM_AUTHREQUIRED);
+ config_set_bool(destination, SECTION_NAME, PARAM_AUTHREQUIRED, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_AUTHREQUIRED);
+ }
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_SECRET)) {
+ const char* value = config_get_string(source, SECTION_NAME, PARAM_SECRET);
+ config_set_string(destination, SECTION_NAME, PARAM_SECRET, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_SECRET);
+ }
+
+ if(config_has_user_value(source, SECTION_NAME, PARAM_SALT)) {
+ const char* value = config_get_string(source, SECTION_NAME, PARAM_SALT);
+ config_set_string(destination, SECTION_NAME, PARAM_SALT, value);
+
+ config_remove_value(source, SECTION_NAME, PARAM_SALT);
+ }
+
+ config_save(destination);
+}
diff --git a/src/Config.h b/src/Config.h
index 4ff8d393..73f04521 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -18,6 +18,8 @@ with this program. If not, see
#pragma once
+#include
+#include
#include
#include
@@ -32,6 +34,10 @@ class Config {
~Config();
void Load();
void Save();
+ void SetDefaults();
+ config_t* GetConfigStore();
+
+ void MigrateFromGlobalSettings();
void SetPassword(QString password);
bool CheckAuth(QString userChallenge);
@@ -52,5 +58,6 @@ class Config {
bool SettingsLoaded;
private:
+ static void OnFrontendEvent(enum obs_frontend_event event, void* param);
static ConfigPtr _instance;
};
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 19b0a75b..7cf67723 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -390,7 +390,7 @@ QSystemTrayIcon* Utils::GetTrayIcon() {
return main->findChildren().first();
}
-void Utils::SysTrayNotify(QString &text,
+void Utils::SysTrayNotify(QString text,
QSystemTrayIcon::MessageIcon icon, QString title) {
if (!Config::Current()->AlertsEnabled ||
!QSystemTrayIcon::isSystemTrayAvailable() ||
diff --git a/src/Utils.h b/src/Utils.h
index 42a90f73..39e428dd 100644
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -71,7 +71,7 @@ class Utils {
static QSystemTrayIcon* GetTrayIcon();
static void SysTrayNotify(
- QString &text,
+ QString text,
QSystemTrayIcon::MessageIcon n,
QString title = QString("obs-websocket"));
diff --git a/src/WSServer.cpp b/src/WSServer.cpp
index 2a74ee01..bec085b0 100644
--- a/src/WSServer.cpp
+++ b/src/WSServer.cpp
@@ -16,6 +16,9 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see
*/
+#include
+#include
+
#include
#include
#include
@@ -55,6 +58,7 @@ WSServer::WSServer()
_clMutex(QMutex::Recursive)
{
_server.init_asio();
+ _server.set_reuse_addr(true);
_server.set_open_handler(bind(&WSServer::onOpen, this, ::_1));
_server.set_close_handler(bind(&WSServer::onClose, this, ::_1));
@@ -77,12 +81,17 @@ void WSServer::start(quint16 port)
stop();
}
+ _server.reset();
+
_serverPort = port;
websocketpp::lib::error_code errorCode;
_server.listen(_serverPort, errorCode);
if (errorCode) {
+ std::string errorCodeMessage = errorCode.message();
+ blog(LOG_INFO, "server: listen failed: %s", errorCodeMessage.c_str());
+
obs_frontend_push_ui_translation(obs_module_get_string);
QString errorTitle = tr("OBSWebsocket.Server.StartFailed.Title");
QString errorMessage = tr("OBSWebsocket.Server.StartFailed.Message").arg(_serverPort);
@@ -97,7 +106,9 @@ void WSServer::start(quint16 port)
_server.start_accept();
QtConcurrent::run([=]() {
+ blog(LOG_INFO, "io thread started");
_server.run();
+ blog(LOG_INFO, "io thread exited");
});
blog(LOG_INFO, "server started successfully on port %d", _serverPort);
@@ -110,7 +121,16 @@ void WSServer::stop()
}
_server.stop_listening();
- _server.stop();
+ for (connection_hdl hdl : _connections) {
+ _server.close(hdl, websocketpp::close::status::going_away, "Server stopping");
+ }
+ _connections.clear();
+ _connectionProperties.clear();
+
+ while (!_server.stopped()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
blog(LOG_INFO, "server stopped successfully");
}
@@ -173,9 +193,14 @@ void WSServer::onClose(connection_hdl hdl)
_connectionProperties.erase(hdl);
locker.unlock();
- QString clientIp = getRemoteEndpoint(hdl);
- notifyDisconnection(clientIp);
- blog(LOG_INFO, "client %s disconnected", clientIp.toUtf8().constData());
+ auto conn = _server.get_con_from_hdl(hdl);
+ auto localCloseCode = conn->get_local_close_code();
+
+ if (localCloseCode != websocketpp::close::status::going_away) {
+ QString clientIp = getRemoteEndpoint(hdl);
+ notifyDisconnection(clientIp);
+ blog(LOG_INFO, "client %s disconnected", clientIp.toUtf8().constData());
+ }
}
QString WSServer::getRemoteEndpoint(connection_hdl hdl)
diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp
index f3a52e69..615d0782 100644
--- a/src/obs-websocket.cpp
+++ b/src/obs-websocket.cpp
@@ -47,6 +47,7 @@ bool obs_module_load(void) {
// Core setup
auto config = Config::Current();
+ config->MigrateFromGlobalSettings(); // TODO remove this on the next minor jump
config->Load();
WSEvents::ResetCurrent(WSServer::Current());