mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Merge pull request #265 from Palakis/websocketpp-4.x
Replace QWebSocketServer with websocket++ in 4.x
This commit is contained in:
commit
be6d9791f5
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[submodule "deps/websocketpp"]
|
||||||
|
path = deps/websocketpp
|
||||||
|
url = https://github.com/zaphoyd/websocketpp.git
|
||||||
|
[submodule "deps/asio"]
|
||||||
|
path = deps/asio
|
||||||
|
url = https://github.com/chriskohlhoff/asio.git
|
@ -20,6 +20,7 @@ echo "[obs-websocket] Building 'obs-websocket' for macOS."
|
|||||||
mkdir -p build && cd build
|
mkdir -p build && cd build
|
||||||
cmake .. \
|
cmake .. \
|
||||||
-DQTDIR=/usr/local/opt/qt \
|
-DQTDIR=/usr/local/opt/qt \
|
||||||
|
-DBOOST_ROOT=/usr/local/opt/boost \
|
||||||
-DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \
|
-DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \
|
||||||
-DLIBOBS_LIB=../../obs-studio/libobs \
|
-DLIBOBS_LIB=../../obs-studio/libobs \
|
||||||
-DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
|
-DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
|
||||||
|
@ -11,7 +11,8 @@ apt-get install -y \
|
|||||||
checkinstall \
|
checkinstall \
|
||||||
cmake \
|
cmake \
|
||||||
obs-studio \
|
obs-studio \
|
||||||
libqt5websockets5-dev
|
qtbase5-dev \
|
||||||
|
libboost-all-dev
|
||||||
|
|
||||||
# Dirty hack
|
# Dirty hack
|
||||||
wget -O /usr/include/obs/obs-frontend-api.h https://raw.githubusercontent.com/obsproject/obs-studio/master/UI/obs-frontend-api/obs-frontend-api.h
|
wget -O /usr/include/obs/obs-frontend-api.h https://raw.githubusercontent.com/obsproject/obs-studio/master/UI/obs-frontend-api/obs-frontend-api.h
|
||||||
|
@ -12,123 +12,6 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>CHILDREN</key>
|
<key>CHILDREN</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array/>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>../../build/QtNetwork</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>292</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>3</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>CHILDREN</key>
|
|
||||||
<array/>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>../../build/QtWebSockets</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>292</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>3</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>bin</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>509</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>Resources</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>509</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>Contents</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>509</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>OBS.app</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>509</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>GID</key>
|
|
||||||
<integer>80</integer>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>Applications</string>
|
|
||||||
<key>PATH_TYPE</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>PERMISSIONS</key>
|
|
||||||
<integer>509</integer>
|
|
||||||
<key>TYPE</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>UID</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
<dict>
|
||||||
<key>CHILDREN</key>
|
<key>CHILDREN</key>
|
||||||
<array>
|
<array>
|
||||||
|
@ -12,9 +12,6 @@ fi
|
|||||||
echo "[obs-websocket] Preparing package build"
|
echo "[obs-websocket] Preparing package build"
|
||||||
export QT_CELLAR_PREFIX="$(/usr/bin/find /usr/local/Cellar/qt -d 1 | sort -t '.' -k 1,1n -k 2,2n -k 3,3n | tail -n 1)"
|
export QT_CELLAR_PREFIX="$(/usr/bin/find /usr/local/Cellar/qt -d 1 | sort -t '.' -k 1,1n -k 2,2n -k 3,3n | tail -n 1)"
|
||||||
|
|
||||||
export WS_LIB="/usr/local/opt/qt/lib/QtWebSockets.framework/QtWebSockets"
|
|
||||||
export NET_LIB="/usr/local/opt/qt/lib/QtNetwork.framework/QtNetwork"
|
|
||||||
|
|
||||||
export GIT_HASH=$(git rev-parse --short HEAD)
|
export GIT_HASH=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
export VERSION="$GIT_HASH-$TRAVIS_BRANCH"
|
export VERSION="$GIT_HASH-$TRAVIS_BRANCH"
|
||||||
@ -27,46 +24,17 @@ fi
|
|||||||
export FILENAME="obs-websocket-$VERSION.pkg"
|
export FILENAME="obs-websocket-$VERSION.pkg"
|
||||||
export LATEST_FILENAME="obs-websocket-latest-$LATEST_VERSION.pkg"
|
export LATEST_FILENAME="obs-websocket-latest-$LATEST_VERSION.pkg"
|
||||||
|
|
||||||
echo "[obs-websocket] Copying Qt dependencies"
|
|
||||||
if [ ! -f ./build/$(basename $WS_LIB) ]; then cp $WS_LIB ./build; fi
|
|
||||||
if [ ! -f ./build/$(basename $NET_LIB) ]; then cp $NET_LIB ./build; fi
|
|
||||||
|
|
||||||
chmod +rw ./build/QtWebSockets ./build/QtNetwork
|
|
||||||
|
|
||||||
echo "[obs-websocket] Modifying QtNetwork"
|
|
||||||
install_name_tool \
|
|
||||||
-id @rpath/QtNetwork \
|
|
||||||
-change /usr/local/opt/qt/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \
|
|
||||||
-change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
|
|
||||||
./build/QtNetwork
|
|
||||||
|
|
||||||
echo "[obs-websocket] Modifying QtWebSockets"
|
|
||||||
install_name_tool \
|
|
||||||
-id @rpath/QtWebSockets \
|
|
||||||
-change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \
|
|
||||||
-change $QT_CELLAR_PREFIX/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \
|
|
||||||
-change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
|
|
||||||
./build/QtWebSockets
|
|
||||||
|
|
||||||
echo "[obs-websocket] Modifying obs-websocket.so"
|
echo "[obs-websocket] Modifying obs-websocket.so"
|
||||||
install_name_tool \
|
install_name_tool \
|
||||||
-change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \
|
|
||||||
-change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets \
|
-change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets \
|
||||||
-change /usr/local/opt/qt/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \
|
|
||||||
-change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui \
|
-change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui \
|
||||||
-change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
|
-change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
|
||||||
./build/obs-websocket.so
|
./build/obs-websocket.so
|
||||||
|
|
||||||
# Check if replacement worked
|
# Check if replacement worked
|
||||||
echo "[obs-websocket] Dependencies for QtNetwork"
|
|
||||||
otool -L ./build/QtNetwork
|
|
||||||
echo "[obs-websocket] Dependencies for QtWebSockets"
|
|
||||||
otool -L ./build/QtWebSockets
|
|
||||||
echo "[obs-websocket] Dependencies for obs-websocket"
|
echo "[obs-websocket] Dependencies for obs-websocket"
|
||||||
otool -L ./build/obs-websocket.so
|
otool -L ./build/obs-websocket.so
|
||||||
|
|
||||||
chmod -w ./build/QtWebSockets ./build/QtNetwork
|
|
||||||
|
|
||||||
echo "[obs-websocket] Actual package build"
|
echo "[obs-websocket] Actual package build"
|
||||||
packagesbuild ./CI/macos/obs-websocket.pkgproj
|
packagesbuild ./CI/macos/obs-websocket.pkgproj
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ PAGER=cat checkinstall -y --type=debian --fstrans=no --nodoc \
|
|||||||
--backup=no --deldoc=yes --install=no \
|
--backup=no --deldoc=yes --install=no \
|
||||||
--pkgname=obs-websocket --pkgversion="$PKG_VERSION" \
|
--pkgname=obs-websocket --pkgversion="$PKG_VERSION" \
|
||||||
--pkglicense="GPLv2.0" --maintainer="contact@slepin.fr" \
|
--pkglicense="GPLv2.0" --maintainer="contact@slepin.fr" \
|
||||||
--requires="libqt5websockets5" --pkggroup="video" \
|
--pkggroup="video" \
|
||||||
--pkgsource="https://github.com/Palakis/obs-websocket" \
|
--pkgsource="https://github.com/Palakis/obs-websocket" \
|
||||||
--pakdir="/package"
|
--pakdir="/package"
|
||||||
|
|
||||||
|
@ -6,14 +6,26 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
if (WIN32 OR APPLE)
|
if (WIN32 OR APPLE)
|
||||||
include(external/FindLibObs.cmake)
|
include(external/FindLibObs.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_definitions(-DASIO_STANDALONE)
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (WIN32 OR APPLE)
|
||||||
|
include(external/FindLibObs.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(LibObs REQUIRED)
|
find_package(LibObs REQUIRED)
|
||||||
find_package(Qt5Core REQUIRED)
|
find_package(Qt5Core REQUIRED)
|
||||||
find_package(Qt5WebSockets REQUIRED)
|
|
||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
find_package(Boost REQUIRED)
|
||||||
|
|
||||||
set(obs-websocket_SOURCES
|
set(obs-websocket_SOURCES
|
||||||
src/obs-websocket.cpp
|
src/obs-websocket.cpp
|
||||||
@ -52,13 +64,14 @@ add_library(obs-websocket MODULE
|
|||||||
include_directories(
|
include_directories(
|
||||||
"${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api"
|
"${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api"
|
||||||
${Qt5Core_INCLUDES}
|
${Qt5Core_INCLUDES}
|
||||||
${Qt5WebSockets_INCLUDES}
|
${Qt5Widgets_INCLUDES}
|
||||||
${Qt5Widgets_INCLUDES})
|
${Boost_INCLUDE_DIRS}
|
||||||
|
"${CMAKE_SOURCE_DIR}/deps/asio/asio/include"
|
||||||
|
"${CMAKE_SOURCE_DIR}/deps/websocketpp")
|
||||||
|
|
||||||
target_link_libraries(obs-websocket
|
target_link_libraries(obs-websocket
|
||||||
libobs
|
libobs
|
||||||
Qt5::Core
|
Qt5::Core
|
||||||
Qt5::WebSockets
|
|
||||||
Qt5::Widgets)
|
Qt5::Widgets)
|
||||||
|
|
||||||
# --- End of section ---
|
# --- End of section ---
|
||||||
@ -70,6 +83,8 @@ if(WIN32)
|
|||||||
message(FATAL_ERROR "Could not find OBS Frontend API's library !")
|
message(FATAL_ERROR "Could not find OBS Frontend API's library !")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_definitions(-D_WEBSOCKETPP_CPP11_STL_)
|
||||||
|
|
||||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
set(ARCH_NAME "64bit")
|
set(ARCH_NAME "64bit")
|
||||||
set(OBS_BUILDDIR_ARCH "build64")
|
set(OBS_BUILDDIR_ARCH "build64")
|
||||||
@ -102,8 +117,6 @@ if(WIN32)
|
|||||||
|
|
||||||
COMMAND if $<CONFIG:Release>==1 ("${CMAKE_COMMAND}" -E copy
|
COMMAND if $<CONFIG:Release>==1 ("${CMAKE_COMMAND}" -E copy
|
||||||
"$<TARGET_FILE:obs-websocket>"
|
"$<TARGET_FILE:obs-websocket>"
|
||||||
"${QTDIR}/bin/Qt5WebSockets.dll"
|
|
||||||
"${QTDIR}/bin/Qt5Network.dll"
|
|
||||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
|
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
|
||||||
|
|
||||||
# If config is RelWithDebInfo, package release files
|
# If config is RelWithDebInfo, package release files
|
||||||
@ -118,8 +131,6 @@ if(WIN32)
|
|||||||
|
|
||||||
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy
|
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy
|
||||||
"$<TARGET_FILE:obs-websocket>"
|
"$<TARGET_FILE:obs-websocket>"
|
||||||
"${QTDIR}/bin/Qt5WebSockets.dll"
|
|
||||||
"${QTDIR}/bin/Qt5Network.dll"
|
|
||||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
|
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
|
||||||
|
|
||||||
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy
|
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy
|
||||||
@ -130,8 +141,6 @@ if(WIN32)
|
|||||||
COMMAND if $<CONFIG:Debug>==1 (
|
COMMAND if $<CONFIG:Debug>==1 (
|
||||||
"${CMAKE_COMMAND}" -E copy
|
"${CMAKE_COMMAND}" -E copy
|
||||||
"$<TARGET_FILE:obs-websocket>"
|
"$<TARGET_FILE:obs-websocket>"
|
||||||
"${QTDIR}/bin/Qt5WebSocketsd.dll"
|
|
||||||
"${QTDIR}/bin/Qt5Networkd.dll"
|
|
||||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}")
|
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}")
|
||||||
|
|
||||||
COMMAND if $<CONFIG:Debug>==1 (
|
COMMAND if $<CONFIG:Debug>==1 (
|
||||||
@ -155,11 +164,8 @@ endif()
|
|||||||
|
|
||||||
# --- Linux-specific build settings and tasks ---
|
# --- Linux-specific build settings and tasks ---
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|
||||||
|
|
||||||
set_target_properties(obs-websocket PROPERTIES PREFIX "")
|
set_target_properties(obs-websocket PROPERTIES PREFIX "")
|
||||||
target_link_libraries(obs-websocket
|
target_link_libraries(obs-websocket obs-frontend-api)
|
||||||
obs-frontend-api)
|
|
||||||
|
|
||||||
file(GLOB locale_files data/locale/*.ini)
|
file(GLOB locale_files data/locale/*.ini)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ install:
|
|||||||
- 7z x dependencies2015.zip -odependencies2015
|
- 7z x dependencies2015.zip -odependencies2015
|
||||||
- set DepsPath32=%CD%\dependencies2015\win32
|
- set DepsPath32=%CD%\dependencies2015\win32
|
||||||
- set DepsPath64=%CD%\dependencies2015\win64
|
- set DepsPath64=%CD%\dependencies2015\win64
|
||||||
|
- set BoostRoot=C:\Libraries\boost_1_67_0
|
||||||
- call C:\projects\obs-websocket\CI\install-setup-qt.cmd
|
- call C:\projects\obs-websocket\CI\install-setup-qt.cmd
|
||||||
- set build_config=RelWithDebInfo
|
- set build_config=RelWithDebInfo
|
||||||
- call C:\projects\obs-websocket\CI\install-build-obs.cmd
|
- call C:\projects\obs-websocket\CI\install-build-obs.cmd
|
||||||
@ -15,9 +16,9 @@ install:
|
|||||||
- mkdir build32
|
- mkdir build32
|
||||||
- mkdir build64
|
- mkdir build64
|
||||||
- cd ./build32
|
- cd ./build32
|
||||||
- cmake -G "Visual Studio 14 2015" -DQTDIR="%QTDIR32%" -DLibObs_DIR="C:\projects\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
- cmake -G "Visual Studio 14 2015" -DQTDIR="%QTDIR32%" -DBOOST_ROOT="%BoostRoot%" -DLibObs_DIR="C:\projects\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
||||||
- cd ../build64
|
- cd ../build64
|
||||||
- cmake -G "Visual Studio 14 2015 Win64" -DQTDIR="%QTDIR64%" -DLibObs_DIR="C:\projects\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
- cmake -G "Visual Studio 14 2015 Win64" -DQTDIR="%QTDIR64%" -DBOOST_ROOT="%BoostRoot%" -DLibObs_DIR="C:\projects\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- call msbuild /m /p:Configuration=%build_config% C:\projects\obs-websocket\build32\obs-websocket.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
- call msbuild /m /p:Configuration=%build_config% C:\projects\obs-websocket\build32\obs-websocket.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||||
|
1
deps/asio
vendored
Submodule
1
deps/asio
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b73dc1d2c0ecb9452a87c26544d7f71e24342df6
|
1
deps/websocketpp
vendored
Submodule
1
deps/websocketpp
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit c6d7e295bf5a0ab9b5f896720cc1a0e0fdc397a7
|
@ -36,7 +36,12 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#define QT_TO_UTF8(str) str.toUtf8().constData()
|
#define QT_TO_UTF8(str) str.toUtf8().constData()
|
||||||
|
|
||||||
Config* Config::_instance = new Config();
|
ConfigPtr Config::_instance = ConfigPtr(new Config());
|
||||||
|
|
||||||
|
ConfigPtr Config::Current()
|
||||||
|
{
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
Config::Config() :
|
Config::Config() :
|
||||||
ServerEnabled(true),
|
ServerEnabled(true),
|
||||||
@ -179,8 +184,3 @@ bool Config::CheckAuth(QString response)
|
|||||||
|
|
||||||
return authSuccess;
|
return authSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config* Config::Current()
|
|
||||||
{
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
10
src/Config.h
10
src/Config.h
@ -20,9 +20,15 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
class Config;
|
||||||
|
typedef QSharedPointer<Config> ConfigPtr;
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
public:
|
public:
|
||||||
|
static ConfigPtr Current();
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
~Config();
|
~Config();
|
||||||
void Load();
|
void Load();
|
||||||
@ -46,10 +52,8 @@ class Config {
|
|||||||
QString SessionChallenge;
|
QString SessionChallenge;
|
||||||
bool SettingsLoaded;
|
bool SettingsLoaded;
|
||||||
|
|
||||||
static Config* Current();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Config* _instance;
|
static ConfigPtr _instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONFIG_H
|
#endif // CONFIG_H
|
||||||
|
@ -376,15 +376,6 @@ void Utils::SysTrayNotify(QString &text,
|
|||||||
trayIcon->showMessage(title, text, icon);
|
trayIcon->showMessage(title, text, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Utils::FormatIPAddress(QHostAddress &addr) {
|
|
||||||
QRegExp v4regex("(::ffff:)(((\\d).){3})", Qt::CaseInsensitive);
|
|
||||||
QString addrString = addr.toString();
|
|
||||||
if (addrString.contains(v4regex)) {
|
|
||||||
addrString = QHostAddress(addr.toIPv4Address()).toString();
|
|
||||||
}
|
|
||||||
return addrString;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Utils::GetRecordingFolder() {
|
const char* Utils::GetRecordingFolder() {
|
||||||
config_t* profile = obs_frontend_get_profile_config();
|
config_t* profile = obs_frontend_get_profile_config();
|
||||||
QString outputMode = config_get_string(profile, "Output", "Mode");
|
QString outputMode = config_get_string(profile, "Output", "Mode");
|
||||||
|
@ -26,7 +26,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QSystemTrayIcon>
|
#include <QSystemTrayIcon>
|
||||||
#include <QHostAddress>
|
|
||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
@ -70,8 +69,6 @@ class Utils {
|
|||||||
QSystemTrayIcon::MessageIcon n,
|
QSystemTrayIcon::MessageIcon n,
|
||||||
QString title = QString("obs-websocket"));
|
QString title = QString("obs-websocket"));
|
||||||
|
|
||||||
static QString FormatIPAddress(QHostAddress &addr);
|
|
||||||
|
|
||||||
static const char* GetRecordingFolder();
|
static const char* GetRecordingFolder();
|
||||||
static bool SetRecordingFolder(const char* path);
|
static bool SetRecordingFolder(const char* path);
|
||||||
|
|
||||||
|
@ -62,9 +62,17 @@ void* calldata_get_ptr(const calldata_t* data, const char* name) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
WSEvents* WSEvents::Instance = nullptr;
|
WSEventsPtr WSEvents::_instance = WSEventsPtr(nullptr);
|
||||||
|
|
||||||
WSEvents::WSEvents(WSServer* srv) {
|
WSEventsPtr WSEvents::Current() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WSEvents::ResetCurrent(WSServerPtr srv) {
|
||||||
|
_instance = WSEventsPtr(new WSEvents(srv));
|
||||||
|
}
|
||||||
|
|
||||||
|
WSEvents::WSEvents(WSServerPtr srv) {
|
||||||
_srv = srv;
|
_srv = srv;
|
||||||
obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
|
obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
|
||||||
|
|
||||||
@ -214,7 +222,7 @@ void WSEvents::broadcastUpdate(const char* updateType,
|
|||||||
obs_data_apply(update, additionalFields);
|
obs_data_apply(update, additionalFields);
|
||||||
|
|
||||||
QString json = obs_data_get_json(update);
|
QString json = obs_data_get_json(update);
|
||||||
_srv->broadcast(json);
|
_srv->broadcast(json.toStdString());
|
||||||
|
|
||||||
if (Config::Current()->DebugEnabled)
|
if (Config::Current()->DebugEnabled)
|
||||||
blog(LOG_DEBUG, "Update << '%s'", json.toUtf8().constData());
|
blog(LOG_DEBUG, "Update << '%s'", json.toUtf8().constData());
|
||||||
|
@ -22,17 +22,27 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
#include "WSServer.h"
|
#include "WSServer.h"
|
||||||
|
|
||||||
class WSEvents : public QObject {
|
class WSEvents;
|
||||||
Q_OBJECT
|
typedef QSharedPointer<WSEvents> WSEventsPtr;
|
||||||
public:
|
|
||||||
explicit WSEvents(WSServer* srv);
|
class WSEvents : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static WSEventsPtr Current();
|
||||||
|
static void ResetCurrent(WSServerPtr srv);
|
||||||
|
|
||||||
|
explicit WSEvents(WSServerPtr srv);
|
||||||
~WSEvents();
|
~WSEvents();
|
||||||
static void FrontendEventHandler(
|
static void FrontendEventHandler(
|
||||||
enum obs_frontend_event event, void* privateData);
|
enum obs_frontend_event event, void* privateData);
|
||||||
static WSEvents* Instance;
|
|
||||||
void connectSceneSignals(obs_source_t* scene);
|
void connectSceneSignals(obs_source_t* scene);
|
||||||
|
|
||||||
void hookTransitionBeginEvent();
|
void hookTransitionBeginEvent();
|
||||||
@ -44,14 +54,16 @@ class WSEvents : public QObject {
|
|||||||
|
|
||||||
bool HeartbeatIsActive;
|
bool HeartbeatIsActive;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void deferredInitOperations();
|
void deferredInitOperations();
|
||||||
void StreamStatus();
|
void StreamStatus();
|
||||||
void Heartbeat();
|
void Heartbeat();
|
||||||
void TransitionDurationChanged(int ms);
|
void TransitionDurationChanged(int ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WSServer* _srv;
|
static WSEventsPtr _instance;
|
||||||
|
|
||||||
|
WSServerPtr _srv;
|
||||||
OBSSource currentScene;
|
OBSSource currentScene;
|
||||||
|
|
||||||
bool pulse;
|
bool pulse;
|
||||||
|
@ -128,26 +128,23 @@ QSet<QString> WSRequestHandler::authNotRequired {
|
|||||||
"Authenticate"
|
"Authenticate"
|
||||||
};
|
};
|
||||||
|
|
||||||
WSRequestHandler::WSRequestHandler(QWebSocket* client) :
|
WSRequestHandler::WSRequestHandler(QVariantHash& connProperties) :
|
||||||
_messageId(0),
|
_messageId(0),
|
||||||
_requestType(""),
|
_requestType(""),
|
||||||
data(nullptr),
|
data(nullptr),
|
||||||
_client(client)
|
_connProperties(connProperties)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSRequestHandler::processIncomingMessage(QString textMessage) {
|
std::string WSRequestHandler::processIncomingMessage(std::string& textMessage) {
|
||||||
QByteArray msgData = textMessage.toUtf8();
|
std::string msgContainer(textMessage);
|
||||||
const char* msg = msgData.constData();
|
const char* msg = msgContainer.c_str();
|
||||||
|
|
||||||
data = obs_data_create_from_json(msg);
|
data = obs_data_create_from_json(msg);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
if (!msg)
|
|
||||||
msg = "<null pointer>";
|
|
||||||
|
|
||||||
blog(LOG_ERROR, "invalid JSON payload received for '%s'", msg);
|
blog(LOG_ERROR, "invalid JSON payload received for '%s'", msg);
|
||||||
SendErrorResponse("invalid JSON payload");
|
SendErrorResponse("invalid JSON payload");
|
||||||
return;
|
return _response;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config::Current()->DebugEnabled) {
|
if (Config::Current()->DebugEnabled) {
|
||||||
@ -158,18 +155,18 @@ void WSRequestHandler::processIncomingMessage(QString textMessage) {
|
|||||||
|| !hasField("message-id"))
|
|| !hasField("message-id"))
|
||||||
{
|
{
|
||||||
SendErrorResponse("missing request parameters");
|
SendErrorResponse("missing request parameters");
|
||||||
return;
|
return _response;
|
||||||
}
|
}
|
||||||
|
|
||||||
_requestType = obs_data_get_string(data, "request-type");
|
_requestType = obs_data_get_string(data, "request-type");
|
||||||
_messageId = obs_data_get_string(data, "message-id");
|
_messageId = obs_data_get_string(data, "message-id");
|
||||||
|
|
||||||
if (Config::Current()->AuthRequired
|
if (Config::Current()->AuthRequired
|
||||||
&& (_client->property(PROP_AUTHENTICATED).toBool() == false)
|
&& (!authNotRequired.contains(_requestType))
|
||||||
&& (authNotRequired.find(_requestType) == authNotRequired.end()))
|
&& (_connProperties.value(PROP_AUTHENTICATED).toBool() == false))
|
||||||
{
|
{
|
||||||
SendErrorResponse("Not Authenticated");
|
SendErrorResponse("Not Authenticated");
|
||||||
return;
|
return _response;
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]);
|
void (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]);
|
||||||
@ -178,6 +175,8 @@ void WSRequestHandler::processIncomingMessage(QString textMessage) {
|
|||||||
handlerFunc(this);
|
handlerFunc(this);
|
||||||
else
|
else
|
||||||
SendErrorResponse("invalid request type");
|
SendErrorResponse("invalid request type");
|
||||||
|
|
||||||
|
return _response;
|
||||||
}
|
}
|
||||||
|
|
||||||
WSRequestHandler::~WSRequestHandler() {
|
WSRequestHandler::~WSRequestHandler() {
|
||||||
@ -215,11 +214,10 @@ void WSRequestHandler::SendErrorResponse(obs_data_t* additionalFields) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WSRequestHandler::SendResponse(obs_data_t* response) {
|
void WSRequestHandler::SendResponse(obs_data_t* response) {
|
||||||
QString json = obs_data_get_json(response);
|
_response = obs_data_get_json(response);
|
||||||
_client->sendTextMessage(json);
|
|
||||||
|
|
||||||
if (Config::Current()->DebugEnabled)
|
if (Config::Current()->DebugEnabled)
|
||||||
blog(LOG_DEBUG, "Response << '%s'", json.toUtf8().constData());
|
blog(LOG_DEBUG, "Response << '%s'", _response.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WSRequestHandler::hasField(QString name) {
|
bool WSRequestHandler::hasField(QString name) {
|
||||||
|
@ -22,8 +22,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QWebSocket>
|
#include <QVariantHash>
|
||||||
#include <QWebSocketServer>
|
|
||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
@ -34,15 +33,16 @@ class WSRequestHandler : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WSRequestHandler(QWebSocket* client);
|
explicit WSRequestHandler(QVariantHash& connProperties);
|
||||||
~WSRequestHandler();
|
~WSRequestHandler();
|
||||||
void processIncomingMessage(QString textMessage);
|
std::string processIncomingMessage(std::string& textMessage);
|
||||||
bool hasField(QString name);
|
bool hasField(QString name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWebSocket* _client;
|
|
||||||
const char* _messageId;
|
const char* _messageId;
|
||||||
const char* _requestType;
|
const char* _requestType;
|
||||||
|
std::string _response;
|
||||||
|
QVariantHash& _connProperties;
|
||||||
OBSDataAutoRelease data;
|
OBSDataAutoRelease data;
|
||||||
|
|
||||||
void SendOKResponse(obs_data_t* additionalFields = NULL);
|
void SendOKResponse(obs_data_t* additionalFields = NULL);
|
||||||
|
@ -85,20 +85,24 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req->_connProperties.value(PROP_AUTHENTICATED).toBool() == true) {
|
||||||
|
req->SendErrorResponse("already authenticated");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString auth = obs_data_get_string(req->data, "auth");
|
QString auth = obs_data_get_string(req->data, "auth");
|
||||||
if (auth.isEmpty()) {
|
if (auth.isEmpty()) {
|
||||||
req->SendErrorResponse("auth not specified!");
|
req->SendErrorResponse("auth not specified!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((req->_client->property(PROP_AUTHENTICATED).toBool() == false)
|
if (Config::Current()->CheckAuth(auth) == false) {
|
||||||
&& Config::Current()->CheckAuth(auth))
|
|
||||||
{
|
|
||||||
req->_client->setProperty(PROP_AUTHENTICATED, true);
|
|
||||||
req->SendOKResponse();
|
|
||||||
} else {
|
|
||||||
req->SendErrorResponse("Authentication Failed.");
|
req->SendErrorResponse("Authentication Failed.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req->_connProperties.insert(PROP_AUTHENTICATED, true);
|
||||||
|
req->SendOKResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,12 +121,12 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WSEvents::Instance->HeartbeatIsActive =
|
auto events = WSEvents::Current();
|
||||||
obs_data_get_bool(req->data, "enable");
|
|
||||||
|
events->HeartbeatIsActive = obs_data_get_bool(req->data, "enable");
|
||||||
|
|
||||||
OBSDataAutoRelease response = obs_data_create();
|
OBSDataAutoRelease response = obs_data_create();
|
||||||
obs_data_set_bool(response, "enable",
|
obs_data_set_bool(response, "enable", events->HeartbeatIsActive);
|
||||||
WSEvents::Instance->HeartbeatIsActive);
|
|
||||||
req->SendOKResponse(response);
|
req->SendOKResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
* @since 0.3
|
* @since 0.3
|
||||||
*/
|
*/
|
||||||
void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req) {
|
void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req) {
|
||||||
|
auto events = WSEvents::Current();
|
||||||
|
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
|
obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
|
||||||
obs_data_set_bool(data, "recording", obs_frontend_recording_active());
|
obs_data_set_bool(data, "recording", obs_frontend_recording_active());
|
||||||
@ -28,13 +30,13 @@
|
|||||||
|
|
||||||
const char* tc = nullptr;
|
const char* tc = nullptr;
|
||||||
if (obs_frontend_streaming_active()) {
|
if (obs_frontend_streaming_active()) {
|
||||||
tc = WSEvents::Instance->GetStreamingTimecode();
|
tc = events->GetStreamingTimecode();
|
||||||
obs_data_set_string(data, "stream-timecode", tc);
|
obs_data_set_string(data, "stream-timecode", tc);
|
||||||
bfree((void*)tc);
|
bfree((void*)tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obs_frontend_recording_active()) {
|
if (obs_frontend_recording_active()) {
|
||||||
tc = WSEvents::Instance->GetRecordingTimecode();
|
tc = events->GetRecordingTimecode();
|
||||||
obs_data_set_string(data, "rec-timecode", tc);
|
obs_data_set_string(data, "rec-timecode", tc);
|
||||||
bfree((void*)tc);
|
bfree((void*)tc);
|
||||||
}
|
}
|
||||||
|
235
src/WSServer.cpp
235
src/WSServer.cpp
@ -16,11 +16,11 @@ 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 <QtWebSockets/QWebSocket>
|
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QByteArray>
|
#include <QtCore/QByteArray>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
#include "WSServer.h"
|
#include "WSServer.h"
|
||||||
@ -30,139 +30,162 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
QT_USE_NAMESPACE
|
QT_USE_NAMESPACE
|
||||||
|
|
||||||
WSServer* WSServer::Instance = nullptr;
|
using websocketpp::lib::placeholders::_1;
|
||||||
|
using websocketpp::lib::placeholders::_2;
|
||||||
|
using websocketpp::lib::bind;
|
||||||
|
|
||||||
WSServer::WSServer(QObject* parent)
|
WSServerPtr WSServer::_instance = WSServerPtr(nullptr);
|
||||||
: QObject(parent),
|
|
||||||
_wsServer(Q_NULLPTR),
|
WSServerPtr WSServer::Current()
|
||||||
_clients(),
|
{
|
||||||
|
if (!_instance) {
|
||||||
|
ResetCurrent();
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WSServer::ResetCurrent()
|
||||||
|
{
|
||||||
|
_instance = WSServerPtr(new WSServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
WSServer::WSServer()
|
||||||
|
: QObject(nullptr),
|
||||||
|
_connections(),
|
||||||
_clMutex(QMutex::Recursive)
|
_clMutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
_wsServer = new QWebSocketServer(
|
_server.init_asio();
|
||||||
QStringLiteral("obs-websocket"),
|
|
||||||
QWebSocketServer::NonSecureMode);
|
_server.set_open_handler(bind(&WSServer::onOpen, this, ::_1));
|
||||||
|
_server.set_close_handler(bind(&WSServer::onClose, this, ::_1));
|
||||||
|
_server.set_message_handler(bind(&WSServer::onMessage, this, ::_1, ::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
WSServer::~WSServer() {
|
WSServer::~WSServer()
|
||||||
Stop();
|
{
|
||||||
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::Start(quint16 port) {
|
void WSServer::start(quint16 port)
|
||||||
if (port == _wsServer->serverPort())
|
{
|
||||||
|
if (_server.is_listening() && port == _serverPort) {
|
||||||
|
blog(LOG_INFO, "WebSocketsServer::start: server already on this port. no restart needed");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(_wsServer->isListening())
|
|
||||||
Stop();
|
|
||||||
|
|
||||||
bool serverStarted = _wsServer->listen(QHostAddress::Any, port);
|
|
||||||
if (serverStarted) {
|
|
||||||
blog(LOG_INFO, "server started successfully on TCP port %d", port);
|
|
||||||
|
|
||||||
connect(_wsServer, SIGNAL(newConnection()),
|
|
||||||
this, SLOT(onNewConnection()));
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
QString errorString = _wsServer->errorString();
|
|
||||||
blog(LOG_ERROR,
|
|
||||||
"error: failed to start server on TCP port %d: %s",
|
|
||||||
port, errorString.toUtf8().constData());
|
|
||||||
|
|
||||||
QMainWindow* mainWindow = (QMainWindow*)obs_frontend_get_main_window();
|
if (_server.is_listening()) {
|
||||||
|
stop();
|
||||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
|
||||||
QString title = tr("OBSWebsocket.Server.StartFailed.Title");
|
|
||||||
QString msg = tr("OBSWebsocket.Server.StartFailed.Message").arg(port);
|
|
||||||
obs_frontend_pop_ui_translation();
|
|
||||||
|
|
||||||
QMessageBox::warning(mainWindow, title, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_serverPort = port;
|
||||||
|
|
||||||
|
_server.listen(_serverPort);
|
||||||
|
_server.start_accept();
|
||||||
|
|
||||||
|
QtConcurrent::run([=]() {
|
||||||
|
_server.run();
|
||||||
|
});
|
||||||
|
|
||||||
|
blog(LOG_INFO, "server started successfully on port %d", _serverPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::Stop() {
|
void WSServer::stop()
|
||||||
QMutexLocker locker(&_clMutex);
|
{
|
||||||
for(QWebSocket* pClient : _clients) {
|
if (!_server.is_listening()) {
|
||||||
pClient->close();
|
return;
|
||||||
}
|
}
|
||||||
locker.unlock();
|
|
||||||
|
|
||||||
_wsServer->close();
|
|
||||||
|
|
||||||
|
_server.stop_listening();
|
||||||
|
_server.stop();
|
||||||
blog(LOG_INFO, "server stopped successfully");
|
blog(LOG_INFO, "server stopped successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::broadcast(QString message) {
|
void WSServer::broadcast(std::string message)
|
||||||
|
{
|
||||||
QMutexLocker locker(&_clMutex);
|
QMutexLocker locker(&_clMutex);
|
||||||
for(QWebSocket* pClient : _clients) {
|
for (connection_hdl hdl : _connections) {
|
||||||
if (Config::Current()->AuthRequired
|
if (Config::Current()->AuthRequired) {
|
||||||
&& (pClient->property(PROP_AUTHENTICATED).toBool() == false)) {
|
bool authenticated = _connectionProperties[hdl].value(PROP_AUTHENTICATED).toBool();
|
||||||
// Skip this client if unauthenticated
|
if (!authenticated) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pClient->sendTextMessage(message);
|
_server.send(hdl, message, websocketpp::frame::opcode::text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::onNewConnection() {
|
void WSServer::onOpen(connection_hdl hdl)
|
||||||
QWebSocket* pSocket = _wsServer->nextPendingConnection();
|
{
|
||||||
if (pSocket) {
|
QMutexLocker locker(&_clMutex);
|
||||||
connect(pSocket, SIGNAL(textMessageReceived(const QString&)),
|
_connections.insert(hdl);
|
||||||
this, SLOT(onTextMessageReceived(QString)));
|
locker.unlock();
|
||||||
connect(pSocket, SIGNAL(disconnected()),
|
|
||||||
this, SLOT(onSocketDisconnected()));
|
|
||||||
|
|
||||||
pSocket->setProperty(PROP_AUTHENTICATED, false);
|
QString clientIp = getRemoteEndpoint(hdl);
|
||||||
|
notifyConnection(clientIp);
|
||||||
QMutexLocker locker(&_clMutex);
|
blog(LOG_INFO, "new client connection from %s", clientIp.toUtf8().constData());
|
||||||
_clients << pSocket;
|
|
||||||
locker.unlock();
|
|
||||||
|
|
||||||
QHostAddress clientAddr = pSocket->peerAddress();
|
|
||||||
QString clientIp = Utils::FormatIPAddress(clientAddr);
|
|
||||||
|
|
||||||
blog(LOG_INFO, "new client connection from %s:%d",
|
|
||||||
clientIp.toUtf8().constData(), pSocket->peerPort());
|
|
||||||
|
|
||||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
|
||||||
QString title = tr("OBSWebsocket.NotifyConnect.Title");
|
|
||||||
QString msg = tr("OBSWebsocket.NotifyConnect.Message")
|
|
||||||
.arg(Utils::FormatIPAddress(clientAddr));
|
|
||||||
obs_frontend_pop_ui_translation();
|
|
||||||
|
|
||||||
Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::onTextMessageReceived(QString message) {
|
void WSServer::onMessage(connection_hdl hdl, server::message_ptr message)
|
||||||
QWebSocket* pSocket = qobject_cast<QWebSocket*>(sender());
|
{
|
||||||
if (pSocket) {
|
auto opcode = message->get_opcode();
|
||||||
WSRequestHandler handler(pSocket);
|
if (opcode != websocketpp::frame::opcode::text) {
|
||||||
handler.processIncomingMessage(message);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string payload = message->get_payload();
|
||||||
|
|
||||||
|
QMutexLocker locker(&_clMutex);
|
||||||
|
QVariantHash connProperties = _connectionProperties[hdl];
|
||||||
|
locker.unlock();
|
||||||
|
|
||||||
|
WSRequestHandler handler(connProperties);
|
||||||
|
std::string response = handler.processIncomingMessage(payload);
|
||||||
|
|
||||||
|
_server.send(hdl, response, websocketpp::frame::opcode::text);
|
||||||
|
|
||||||
|
locker.relock();
|
||||||
|
// In multithreaded processing this would be problematic to put back
|
||||||
|
// a copy of the connection properties, because there might conflicts
|
||||||
|
// between several simultaneous handlers.
|
||||||
|
// In our case, it's fine because all messages are processed in one thread.
|
||||||
|
_connectionProperties[hdl] = connProperties;
|
||||||
|
locker.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::onSocketDisconnected() {
|
void WSServer::onClose(connection_hdl hdl)
|
||||||
QWebSocket* pSocket = qobject_cast<QWebSocket*>(sender());
|
{
|
||||||
if (pSocket) {
|
QMutexLocker locker(&_clMutex);
|
||||||
pSocket->setProperty(PROP_AUTHENTICATED, false);
|
_connections.erase(hdl);
|
||||||
|
_connectionProperties.erase(hdl);
|
||||||
|
locker.unlock();
|
||||||
|
|
||||||
QMutexLocker locker(&_clMutex);
|
QString clientIp = getRemoteEndpoint(hdl);
|
||||||
_clients.removeAll(pSocket);
|
notifyDisconnection(clientIp);
|
||||||
locker.unlock();
|
blog(LOG_INFO, "client %s disconnected", clientIp.toUtf8().constData());
|
||||||
|
}
|
||||||
pSocket->deleteLater();
|
|
||||||
|
QString WSServer::getRemoteEndpoint(connection_hdl hdl)
|
||||||
QHostAddress clientAddr = pSocket->peerAddress();
|
{
|
||||||
QString clientIp = Utils::FormatIPAddress(clientAddr);
|
auto conn = _server.get_con_from_hdl(hdl);
|
||||||
|
return QString::fromStdString(conn->get_remote_endpoint());
|
||||||
blog(LOG_INFO, "client %s:%d disconnected",
|
}
|
||||||
clientIp.toUtf8().constData(), pSocket->peerPort());
|
|
||||||
|
void WSServer::notifyConnection(QString clientIp)
|
||||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
{
|
||||||
QString title = tr("OBSWebsocket.NotifyDisconnect.Title");
|
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||||
QString msg = tr("OBSWebsocket.NotifyDisconnect.Message")
|
QString title = tr("OBSWebsocket.NotifyConnect.Title");
|
||||||
.arg(Utils::FormatIPAddress(clientAddr));
|
QString msg = tr("OBSWebsocket.NotifyConnect.Message").arg(clientIp);
|
||||||
obs_frontend_pop_ui_translation();
|
obs_frontend_pop_ui_translation();
|
||||||
|
|
||||||
Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title);
|
Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WSServer::notifyDisconnection(QString clientIp)
|
||||||
|
{
|
||||||
|
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||||
|
QString title = tr("OBSWebsocket.NotifyDisconnect.Title");
|
||||||
|
QString msg = tr("OBSWebsocket.NotifyDisconnect.Message").arg(clientIp);
|
||||||
|
obs_frontend_pop_ui_translation();
|
||||||
|
|
||||||
|
Utils::SysTrayNotify(msg, QSystemTrayIcon::Information, title);
|
||||||
}
|
}
|
||||||
|
@ -20,33 +20,58 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
#define WSSERVER_H
|
#define WSSERVER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QList>
|
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QVariantHash>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <websocketpp/config/asio_no_tls.hpp>
|
||||||
|
#include <websocketpp/server.hpp>
|
||||||
|
|
||||||
#include "WSRequestHandler.h"
|
#include "WSRequestHandler.h"
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
|
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
|
||||||
QT_FORWARD_DECLARE_CLASS(QWebSocket)
|
QT_FORWARD_DECLARE_CLASS(QWebSocket)
|
||||||
|
|
||||||
class WSServer : public QObject {
|
using websocketpp::connection_hdl;
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WSServer(QObject* parent = Q_NULLPTR);
|
|
||||||
virtual ~WSServer();
|
|
||||||
void Start(quint16 port);
|
|
||||||
void Stop();
|
|
||||||
void broadcast(QString message);
|
|
||||||
static WSServer* Instance;
|
|
||||||
|
|
||||||
private slots:
|
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||||
void onNewConnection();
|
|
||||||
void onTextMessageReceived(QString message);
|
|
||||||
void onSocketDisconnected();
|
|
||||||
|
|
||||||
private:
|
class WSServer;
|
||||||
QWebSocketServer* _wsServer;
|
typedef QSharedPointer<WSServer> WSServerPtr;
|
||||||
QList<QWebSocket*> _clients;
|
|
||||||
QMutex _clMutex;
|
class WSServer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static WSServerPtr Current();
|
||||||
|
static void ResetCurrent();
|
||||||
|
|
||||||
|
explicit WSServer();
|
||||||
|
virtual ~WSServer();
|
||||||
|
void start(quint16 port);
|
||||||
|
void stop();
|
||||||
|
void broadcast(std::string message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static WSServerPtr _instance;
|
||||||
|
|
||||||
|
void onOpen(connection_hdl hdl);
|
||||||
|
void onMessage(connection_hdl hdl, server::message_ptr message);
|
||||||
|
void onClose(connection_hdl hdl);
|
||||||
|
|
||||||
|
QString getRemoteEndpoint(connection_hdl hdl);
|
||||||
|
void notifyConnection(QString clientIp);
|
||||||
|
void notifyDisconnection(QString clientIp);
|
||||||
|
|
||||||
|
server _server;
|
||||||
|
quint16 _serverPort;
|
||||||
|
std::set<connection_hdl, std::owner_less<connection_hdl>> _connections;
|
||||||
|
std::map<connection_hdl, QVariantHash, std::owner_less<connection_hdl>> _connectionProperties;
|
||||||
|
QMutex _clMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WSSERVER_H
|
#endif // WSSERVER_H
|
||||||
|
@ -41,7 +41,7 @@ SettingsDialog::SettingsDialog(QWidget* parent) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::showEvent(QShowEvent* event) {
|
void SettingsDialog::showEvent(QShowEvent* event) {
|
||||||
Config* conf = Config::Current();
|
auto conf = Config::Current();
|
||||||
|
|
||||||
ui->serverEnabled->setChecked(conf->ServerEnabled);
|
ui->serverEnabled->setChecked(conf->ServerEnabled);
|
||||||
ui->serverPort->setValue(conf->ServerPort);
|
ui->serverPort->setValue(conf->ServerPort);
|
||||||
@ -68,7 +68,7 @@ void SettingsDialog::AuthCheckboxChanged() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::FormAccepted() {
|
void SettingsDialog::FormAccepted() {
|
||||||
Config* conf = Config::Current();
|
auto conf = Config::Current();
|
||||||
|
|
||||||
conf->ServerEnabled = ui->serverEnabled->isChecked();
|
conf->ServerEnabled = ui->serverEnabled->isChecked();
|
||||||
conf->ServerPort = ui->serverPort->value();
|
conf->ServerPort = ui->serverPort->value();
|
||||||
@ -94,9 +94,9 @@ void SettingsDialog::FormAccepted() {
|
|||||||
conf->Save();
|
conf->Save();
|
||||||
|
|
||||||
if (conf->ServerEnabled)
|
if (conf->ServerEnabled)
|
||||||
WSServer::Instance->Start(conf->ServerPort);
|
WSServer::Current()->start(conf->ServerPort);
|
||||||
else
|
else
|
||||||
WSServer::Instance->Stop();
|
WSServer::Current()->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsDialog::~SettingsDialog() {
|
SettingsDialog::~SettingsDialog() {
|
||||||
|
@ -45,18 +45,19 @@ bool obs_module_load(void) {
|
|||||||
QT_VERSION_STR, qVersion());
|
QT_VERSION_STR, qVersion());
|
||||||
|
|
||||||
// Core setup
|
// Core setup
|
||||||
Config* config = Config::Current();
|
auto config = Config::Current();
|
||||||
config->Load();
|
config->Load();
|
||||||
|
|
||||||
WSServer::Instance = new WSServer();
|
WSEvents::ResetCurrent(WSServer::Current());
|
||||||
WSEvents::Instance = new WSEvents(WSServer::Instance);
|
|
||||||
|
|
||||||
if (config->ServerEnabled)
|
if (config->ServerEnabled) {
|
||||||
WSServer::Instance->Start(config->ServerPort);
|
WSServer::Current()->start(config->ServerPort);
|
||||||
|
}
|
||||||
|
|
||||||
// UI setup
|
// UI setup
|
||||||
QAction* menu_action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
QAction* menu_action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||||
obs_module_text("OBSWebsocket.Menu.SettingsItem"));
|
obs_module_text("OBSWebsocket.Menu.SettingsItem")
|
||||||
|
);
|
||||||
|
|
||||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||||
QMainWindow* main_window = (QMainWindow*)obs_frontend_get_main_window();
|
QMainWindow* main_window = (QMainWindow*)obs_frontend_get_main_window();
|
||||||
@ -75,6 +76,7 @@ bool obs_module_load(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void obs_module_unload() {
|
void obs_module_unload() {
|
||||||
|
WSServer::Current()->stop();
|
||||||
blog(LOG_INFO, "goodbye!");
|
blog(LOG_INFO, "goodbye!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user