Merge pull request #304 from Palakis/feature/269-settings-per-profile

Move settings to profile
This commit is contained in:
Stéphane Lepin 2019-04-22 16:29:01 +02:00 committed by GitHub
commit eb84f677cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 189 additions and 46 deletions

View File

@ -12,3 +12,6 @@ OBSWebsocket.NotifyDisconnect.Title="WebSocket client disconnected"
OBSWebsocket.NotifyDisconnect.Message="Client %1 disconnected" OBSWebsocket.NotifyDisconnect.Message="Client %1 disconnected"
OBSWebsocket.Server.StartFailed.Title="WebSocket Server failure" 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.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."

View File

@ -17,10 +17,10 @@ with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <util/config-file.h>
#include <QtCore/QCryptographicHash> #include <QtCore/QCryptographicHash>
#include <QtCore/QTime> #include <QtCore/QTime>
#include <QtWidgets/QSystemTrayIcon>
#define SECTION_NAME "WebsocketAPI" #define SECTION_NAME "WebsocketAPI"
#define PARAM_ENABLE "ServerEnabled" #define PARAM_ENABLE "ServerEnabled"
@ -31,8 +31,10 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#define PARAM_SECRET "AuthSecret" #define PARAM_SECRET "AuthSecret"
#define PARAM_SALT "AuthSalt" #define PARAM_SALT "AuthSalt"
#include "Config.h"
#include "Utils.h" #include "Utils.h"
#include "WSServer.h"
#include "Config.h"
#define QT_TO_UTF8(str) str.toUtf8().constData() #define QT_TO_UTF8(str) str.toUtf8().constData()
@ -55,8 +57,55 @@ Config::Config() :
{ {
qsrand(QTime::currentTime().msec()); 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 // OBS Config defaults
config_t* obsConfig = obs_frontend_get_global_config(); config_t* obsConfig = GetConfigStore();
if (obsConfig) { if (obsConfig) {
config_set_default_bool(obsConfig, config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_ENABLE, ServerEnabled); SECTION_NAME, PARAM_ENABLE, ServerEnabled);
@ -75,46 +124,11 @@ Config::Config() :
config_set_default_string(obsConfig, config_set_default_string(obsConfig,
SECTION_NAME, PARAM_SALT, QT_TO_UTF8(Salt)); SECTION_NAME, PARAM_SALT, QT_TO_UTF8(Salt));
} }
SessionChallenge = GenerateSalt();
} }
Config::~Config() config_t* Config::GetConfigStore()
{ {
} return obs_frontend_get_profile_config();
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);
} }
QString Config::GenerateSalt() QString Config::GenerateSalt()
@ -184,3 +198,96 @@ bool Config::CheckAuth(QString response)
return authSuccess; return authSuccess;
} }
void Config::OnFrontendEvent(enum obs_frontend_event event, void* param)
{
auto config = reinterpret_cast<Config*>(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);
}

View File

@ -18,6 +18,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#pragma once #pragma once
#include <obs-frontend-api.h>
#include <util/config-file.h>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
@ -32,6 +34,10 @@ class Config {
~Config(); ~Config();
void Load(); void Load();
void Save(); void Save();
void SetDefaults();
config_t* GetConfigStore();
void MigrateFromGlobalSettings();
void SetPassword(QString password); void SetPassword(QString password);
bool CheckAuth(QString userChallenge); bool CheckAuth(QString userChallenge);
@ -52,5 +58,6 @@ class Config {
bool SettingsLoaded; bool SettingsLoaded;
private: private:
static void OnFrontendEvent(enum obs_frontend_event event, void* param);
static ConfigPtr _instance; static ConfigPtr _instance;
}; };

View File

@ -390,7 +390,7 @@ QSystemTrayIcon* Utils::GetTrayIcon() {
return main->findChildren<QSystemTrayIcon*>().first(); return main->findChildren<QSystemTrayIcon*>().first();
} }
void Utils::SysTrayNotify(QString &text, void Utils::SysTrayNotify(QString text,
QSystemTrayIcon::MessageIcon icon, QString title) { QSystemTrayIcon::MessageIcon icon, QString title) {
if (!Config::Current()->AlertsEnabled || if (!Config::Current()->AlertsEnabled ||
!QSystemTrayIcon::isSystemTrayAvailable() || !QSystemTrayIcon::isSystemTrayAvailable() ||

View File

@ -71,7 +71,7 @@ class Utils {
static QSystemTrayIcon* GetTrayIcon(); static QSystemTrayIcon* GetTrayIcon();
static void SysTrayNotify( static void SysTrayNotify(
QString &text, QString text,
QSystemTrayIcon::MessageIcon n, QSystemTrayIcon::MessageIcon n,
QString title = QString("obs-websocket")); QString title = QString("obs-websocket"));

View File

@ -16,6 +16,9 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/> with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include <chrono>
#include <thread>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
@ -55,6 +58,7 @@ WSServer::WSServer()
_clMutex(QMutex::Recursive) _clMutex(QMutex::Recursive)
{ {
_server.init_asio(); _server.init_asio();
_server.set_reuse_addr(true);
_server.set_open_handler(bind(&WSServer::onOpen, this, ::_1)); _server.set_open_handler(bind(&WSServer::onOpen, this, ::_1));
_server.set_close_handler(bind(&WSServer::onClose, this, ::_1)); _server.set_close_handler(bind(&WSServer::onClose, this, ::_1));
@ -77,12 +81,17 @@ void WSServer::start(quint16 port)
stop(); stop();
} }
_server.reset();
_serverPort = port; _serverPort = port;
websocketpp::lib::error_code errorCode; websocketpp::lib::error_code errorCode;
_server.listen(_serverPort, errorCode); _server.listen(_serverPort, errorCode);
if (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); obs_frontend_push_ui_translation(obs_module_get_string);
QString errorTitle = tr("OBSWebsocket.Server.StartFailed.Title"); QString errorTitle = tr("OBSWebsocket.Server.StartFailed.Title");
QString errorMessage = tr("OBSWebsocket.Server.StartFailed.Message").arg(_serverPort); QString errorMessage = tr("OBSWebsocket.Server.StartFailed.Message").arg(_serverPort);
@ -97,7 +106,9 @@ void WSServer::start(quint16 port)
_server.start_accept(); _server.start_accept();
QtConcurrent::run([=]() { QtConcurrent::run([=]() {
blog(LOG_INFO, "io thread started");
_server.run(); _server.run();
blog(LOG_INFO, "io thread exited");
}); });
blog(LOG_INFO, "server started successfully on port %d", _serverPort); blog(LOG_INFO, "server started successfully on port %d", _serverPort);
@ -110,7 +121,16 @@ void WSServer::stop()
} }
_server.stop_listening(); _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"); blog(LOG_INFO, "server stopped successfully");
} }
@ -173,9 +193,14 @@ void WSServer::onClose(connection_hdl hdl)
_connectionProperties.erase(hdl); _connectionProperties.erase(hdl);
locker.unlock(); locker.unlock();
QString clientIp = getRemoteEndpoint(hdl); auto conn = _server.get_con_from_hdl(hdl);
notifyDisconnection(clientIp); auto localCloseCode = conn->get_local_close_code();
blog(LOG_INFO, "client %s disconnected", clientIp.toUtf8().constData());
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) QString WSServer::getRemoteEndpoint(connection_hdl hdl)

View File

@ -47,6 +47,7 @@ bool obs_module_load(void) {
// Core setup // Core setup
auto config = Config::Current(); auto config = Config::Current();
config->MigrateFromGlobalSettings(); // TODO remove this on the next minor jump
config->Load(); config->Load();
WSEvents::ResetCurrent(WSServer::Current()); WSEvents::ResetCurrent(WSServer::Current());