Some updates
This commit is contained in:
parent
9e2249462c
commit
97fd71b69a
572
CMakeLists.txt
572
CMakeLists.txt
@ -1,286 +1,286 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(TeaSpeak-Shared)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if(NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-reorder -Wno-sign-compare -fpermissive -ftemplate-depth=1000 ${MEMORY_DEBUG_FLAGS}")
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
else()
|
||||
#For Windows
|
||||
add_definitions(-D_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING)
|
||||
|
||||
add_compile_options(/wd4996) #'std::result_of_t': warning STL4014: std::result_of and std::result_of_t are deprecated in C++17.
|
||||
endif()
|
||||
|
||||
if(CMAKE_PLATFORM_INCLUDE AND NOT CMAKE_PLATFORM_INCLUDE STREQUAL "")
|
||||
include(${CMAKE_PLATFORM_INCLUDE})
|
||||
endif()
|
||||
|
||||
find_package(TomMath REQUIRED)
|
||||
include_directories(${TomMath_INCLUDE_DIR})
|
||||
|
||||
find_package(TomCrypt REQUIRED)
|
||||
include_directories(${TomCrypt_INCLUDE_DIR})
|
||||
|
||||
find_package(DataPipes REQUIRED)
|
||||
include_directories(${DataPipes_INCLUDE_DIR})
|
||||
|
||||
# LibEvent fucks up the CMAKE_FIND_LIBRARY_SUFFIXES variable
|
||||
if (NOT find_event)
|
||||
function(find_event static)
|
||||
if(static)
|
||||
set(LIBEVENT_STATIC_LINK TRUE)
|
||||
endif()
|
||||
find_package(Libevent REQUIRED)
|
||||
include_directories(${LIBEVENT_INCLUDE_DIRS})
|
||||
endfunction()
|
||||
endif ()
|
||||
find_event(ON)
|
||||
|
||||
find_package(StringVariable REQUIRED)
|
||||
include_directories(${StringVariable_INCLUDE_DIR})
|
||||
|
||||
find_package(Ed25519 REQUIRED)
|
||||
include_directories(${ed25519_INCLUDE_DIR})
|
||||
|
||||
find_package(ThreadPool REQUIRED)
|
||||
include_directories(${ThreadPool_INCLUDE_DIR})
|
||||
if(WIN32)
|
||||
add_definitions(-DWINDOWS) #Required for ThreadPool
|
||||
endif()
|
||||
find_package(spdlog REQUIRED)
|
||||
link_libraries(spdlog::spdlog_header_only) #Its a header only lib so we should be fine :)
|
||||
|
||||
if(NOT TEASPEAK_SERVER)
|
||||
add_definitions(-DNO_OPEN_SSL)
|
||||
add_definitions(-D_HAS_STD_BYTE)
|
||||
#FML
|
||||
else()
|
||||
find_package(CXXTerminal REQUIRED)
|
||||
|
||||
add_definitions(-DHAVE_CXX_TERMINAL)
|
||||
add_definitions(-DHAVE_JSON)
|
||||
set(HAVE_SQLITE3 ON)
|
||||
set(HAVE_OPEN_SSL ON)
|
||||
message("HAVE JSON!")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(CompilerFlags
|
||||
CMAKE_CXX_FLAGS
|
||||
CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_C_FLAGS
|
||||
CMAKE_C_FLAGS_DEBUG
|
||||
CMAKE_C_FLAGS_RELEASE
|
||||
)
|
||||
foreach(CompilerFlag ${CompilerFlags})
|
||||
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
|
||||
endforeach()
|
||||
add_compile_options("/EHsc") #We require exception handling
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3") #-DNDEBUG We want assert!
|
||||
endif()
|
||||
add_definitions(-DUSE_BORINGSSL)
|
||||
include_directories(${LIBRARY_PATH}/boringssl/include/)
|
||||
set(SOURCE_FILES
|
||||
src/misc/rnd.cpp
|
||||
src/misc/time.cpp
|
||||
src/misc/memtracker.cpp
|
||||
src/misc/digest.cpp
|
||||
src/misc/base64.cpp
|
||||
|
||||
#Logger
|
||||
src/log/LogUtils.cpp
|
||||
src/log/LogSinks.cpp
|
||||
|
||||
|
||||
src/qlz/QuickLZ.cpp
|
||||
src/qlz/QuickLZ_L3.cpp
|
||||
src/qlz/QuickLZ_L1.cpp
|
||||
|
||||
src/converters/converter.cpp
|
||||
|
||||
src/query/command3.cpp
|
||||
src/query/command2.cpp
|
||||
src/query/Command.cpp
|
||||
src/query/escape.cpp
|
||||
|
||||
src/protocol/generation.cpp
|
||||
src/protocol/Packet.cpp
|
||||
src/protocol/buffers.cpp
|
||||
src/protocol/buffers_allocator_c.cpp
|
||||
src/PermissionManager.cpp
|
||||
src/Properties.cpp
|
||||
src/BasicChannel.cpp
|
||||
src/Error.cpp
|
||||
src/protocol/CryptHandler.cpp
|
||||
src/protocol/CompressionHandler.cpp
|
||||
src/Variable.cpp
|
||||
src/linked_helper.cpp
|
||||
src/EventLoop.cpp
|
||||
|
||||
src/License.cpp
|
||||
|
||||
src/bbcode/bbcodes.cpp
|
||||
|
||||
src/channel/TreeView.cpp
|
||||
src/protocol/ringbuffer.cpp
|
||||
src/protocol/AcknowledgeManager.cpp
|
||||
)
|
||||
|
||||
set(HEADER_FILES
|
||||
src/misc/base64.h
|
||||
src/misc/endianness.h
|
||||
src/misc/cast.h
|
||||
src/misc/rnd.h
|
||||
src/misc/time.h
|
||||
src/misc/std_unique_ptr.h
|
||||
src/misc/net.h
|
||||
src/misc/lambda.h
|
||||
src/misc/hex.h
|
||||
src/misc/advanced_mutex.h
|
||||
src/misc/memtracker.h
|
||||
src/misc/strobf.h
|
||||
|
||||
src/log/translation.h
|
||||
src/log/LogUtils.h
|
||||
|
||||
src/PermissionManager.h
|
||||
src/protocol/buffers.h
|
||||
src/protocol/Packet.h
|
||||
src/Properties.h
|
||||
src/BasicChannel.h
|
||||
src/Definitions.h
|
||||
src/Error.h
|
||||
src/protocol/CryptHandler.h
|
||||
src/Variable.h
|
||||
src/misc/queue.h
|
||||
|
||||
src/misc/digest.h
|
||||
|
||||
src/bbcode/bbcodes.h
|
||||
|
||||
src/channel/TreeView.h
|
||||
)
|
||||
|
||||
if(HAVE_SQLITE3)
|
||||
set(SOURCE_FILES ${SOURCE_FILES}
|
||||
src/sql/SqlQuery.cpp
|
||||
src/sql/sqlite/SqliteSQL.cpp
|
||||
src/sql/mysql/MySQL.cpp
|
||||
)
|
||||
set(HEADER_FILES ${HEADER_FILES}
|
||||
src/sql/SqlQuery.h
|
||||
src/sql/sqlite/SqliteSQL.h
|
||||
src/sql/mysql/MySQL.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(HAVE_OPEN_SSL)
|
||||
set(SOURCE_FILES ${SOURCE_FILES}
|
||||
src/ssl/SSLManager.cpp
|
||||
)
|
||||
set(HEADER_FILES ${HEADER_FILES}
|
||||
src/ssl/SSLManager.h
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(TeaSpeak STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
target_link_libraries(TeaSpeak PUBLIC threadpool::static jsoncpp_lib)
|
||||
target_compile_options(TeaSpeak PRIVATE "-Wall")
|
||||
|
||||
if (TEASPEAK_SERVER)
|
||||
target_link_libraries(TeaSpeak PUBLIC CXXTerminal::static)
|
||||
endif ()
|
||||
target_include_directories(TeaSpeak PUBLIC src/)
|
||||
install(TARGETS TeaSpeak
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
INSTALL (
|
||||
DIRECTORY ${CMAKE_SOURCE_DIR}/src/
|
||||
DESTINATION include
|
||||
FILES_MATCHING PATTERN "*.h*"
|
||||
)
|
||||
|
||||
set(TEST_LIBRARIES
|
||||
threadpool::static #Static
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
CXXTerminal::static #Static
|
||||
${StringVariable_LIBRARIES_STATIC}
|
||||
${YAML_CPP_LIBRARIES}
|
||||
pthread
|
||||
stdc++fs
|
||||
libevent::core libevent::pthreads
|
||||
opus::static
|
||||
yaml-cpp
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
|
||||
breakpad::static
|
||||
protobuf::libprotobuf
|
||||
jemalloc::shared
|
||||
|
||||
tomcrypt::static
|
||||
tommath::static
|
||||
|
||||
mysqlclient.a
|
||||
jsoncpp_lib
|
||||
${ed25519_LIBRARIES_STATIC}
|
||||
${DataPipes_LIBRARIES_SHARED} # Also includes glib2.0
|
||||
|
||||
openssl::ssl::shared
|
||||
openssl::crypto::shared
|
||||
dl
|
||||
z
|
||||
)
|
||||
include_directories(src/)
|
||||
option(BUILD_TESTS "Enable/disable test building" ON)
|
||||
if(BUILD_TESTS)
|
||||
add_executable(RingTest test/RingTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(RingTest ${TEST_LIBRARIES})
|
||||
|
||||
if(NOT WIN32)
|
||||
add_executable(CommandTest ${SOURCE_FILES} ${HEADER_FILES} test/CommandTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h ../server/MySQLLibSSLFix.c)
|
||||
target_link_libraries(CommandTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(WebsocketTest ${SOURCE_FILES} ${HEADER_FILES} test/WSSTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(WebsocketTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(SQLTest ${SOURCE_FILES} ${HEADER_FILES} test/SQLTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(SQLTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(ChannelTest ${SOURCE_FILES} ${HEADER_FILES} test/ChannelTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(ChannelTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(EndianessTest ${SOURCE_FILES} ${HEADER_FILES} test/EndianessTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(EndianessTest ${TEST_LIBRARIES})
|
||||
|
||||
include_directories(/usr/local/include/breakpad)
|
||||
add_executable(CrashTest test/CrashTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(CrashTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(PorpertyTest test/PropertyTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(PorpertyTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES} src/query/command_unused.h)
|
||||
target_link_libraries(BBTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(LinkedTest test/LinkedTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(LinkedTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(PermissionTest test/PermissionTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(PermissionTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(GenerationTest test/generationTest.cpp ${SOURCE_FILES} ../server/MySQLLibSSLFix.c)
|
||||
target_link_libraries(GenerationTest ${TEST_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(TeaSpeak-Shared)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if(NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-reorder -Wno-sign-compare -fpermissive -ftemplate-depth=1000 ${MEMORY_DEBUG_FLAGS}")
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
else()
|
||||
#For Windows
|
||||
add_definitions(-D_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING)
|
||||
|
||||
add_compile_options(/wd4996) #'std::result_of_t': warning STL4014: std::result_of and std::result_of_t are deprecated in C++17.
|
||||
endif()
|
||||
|
||||
if(CMAKE_PLATFORM_INCLUDE AND NOT CMAKE_PLATFORM_INCLUDE STREQUAL "")
|
||||
include(${CMAKE_PLATFORM_INCLUDE})
|
||||
endif()
|
||||
|
||||
find_package(TomMath REQUIRED)
|
||||
include_directories(${TomMath_INCLUDE_DIR})
|
||||
|
||||
find_package(TomCrypt REQUIRED)
|
||||
include_directories(${TomCrypt_INCLUDE_DIR})
|
||||
|
||||
find_package(DataPipes REQUIRED)
|
||||
include_directories(${DataPipes_INCLUDE_DIR})
|
||||
|
||||
# LibEvent fucks up the CMAKE_FIND_LIBRARY_SUFFIXES variable
|
||||
if (NOT find_event)
|
||||
function(find_event static)
|
||||
if(static)
|
||||
set(LIBEVENT_STATIC_LINK TRUE)
|
||||
endif()
|
||||
find_package(Libevent REQUIRED)
|
||||
include_directories(${LIBEVENT_INCLUDE_DIRS})
|
||||
endfunction()
|
||||
endif ()
|
||||
find_event(ON)
|
||||
|
||||
find_package(StringVariable REQUIRED)
|
||||
include_directories(${StringVariable_INCLUDE_DIR})
|
||||
|
||||
find_package(Ed25519 REQUIRED)
|
||||
include_directories(${ed25519_INCLUDE_DIR})
|
||||
|
||||
find_package(ThreadPool REQUIRED)
|
||||
include_directories(${ThreadPool_INCLUDE_DIR})
|
||||
if(WIN32)
|
||||
add_definitions(-DWINDOWS) #Required for ThreadPool
|
||||
endif()
|
||||
find_package(spdlog REQUIRED)
|
||||
link_libraries(spdlog::spdlog_header_only) #Its a header only lib so we should be fine :)
|
||||
|
||||
if(NOT TEASPEAK_SERVER)
|
||||
add_definitions(-DNO_OPEN_SSL)
|
||||
add_definitions(-D_HAS_STD_BYTE)
|
||||
#FML
|
||||
else()
|
||||
find_package(CXXTerminal REQUIRED)
|
||||
|
||||
add_definitions(-DHAVE_CXX_TERMINAL)
|
||||
add_definitions(-DHAVE_JSON)
|
||||
set(HAVE_SQLITE3 ON)
|
||||
set(HAVE_OPEN_SSL ON)
|
||||
message("HAVE JSON!")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(CompilerFlags
|
||||
CMAKE_CXX_FLAGS
|
||||
CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_C_FLAGS
|
||||
CMAKE_C_FLAGS_DEBUG
|
||||
CMAKE_C_FLAGS_RELEASE
|
||||
)
|
||||
foreach(CompilerFlag ${CompilerFlags})
|
||||
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
|
||||
endforeach()
|
||||
add_compile_options("/EHsc") #We require exception handling
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3") #-DNDEBUG We want assert!
|
||||
endif()
|
||||
add_definitions(-DUSE_BORINGSSL)
|
||||
include_directories(${LIBRARY_PATH}/boringssl/include/)
|
||||
set(SOURCE_FILES
|
||||
src/misc/rnd.cpp
|
||||
src/misc/time.cpp
|
||||
src/misc/memtracker.cpp
|
||||
src/misc/digest.cpp
|
||||
src/misc/base64.cpp
|
||||
|
||||
#Logger
|
||||
src/log/LogUtils.cpp
|
||||
src/log/LogSinks.cpp
|
||||
|
||||
|
||||
src/qlz/QuickLZ.cpp
|
||||
src/qlz/QuickLZ_L3.cpp
|
||||
src/qlz/QuickLZ_L1.cpp
|
||||
|
||||
src/converters/converter.cpp
|
||||
|
||||
src/query/command3.cpp
|
||||
src/query/command2.cpp
|
||||
src/query/Command.cpp
|
||||
src/query/escape.cpp
|
||||
|
||||
src/protocol/generation.cpp
|
||||
src/protocol/Packet.cpp
|
||||
src/protocol/buffers.cpp
|
||||
src/protocol/buffers_allocator_c.cpp
|
||||
src/PermissionManager.cpp
|
||||
src/Properties.cpp
|
||||
src/BasicChannel.cpp
|
||||
src/Error.cpp
|
||||
src/protocol/CryptHandler.cpp
|
||||
src/protocol/CompressionHandler.cpp
|
||||
src/Variable.cpp
|
||||
src/linked_helper.cpp
|
||||
src/EventLoop.cpp
|
||||
|
||||
src/License.cpp
|
||||
|
||||
src/bbcode/bbcodes.cpp
|
||||
|
||||
src/channel/TreeView.cpp
|
||||
src/protocol/ringbuffer.cpp
|
||||
src/protocol/AcknowledgeManager.cpp
|
||||
)
|
||||
|
||||
set(HEADER_FILES
|
||||
src/misc/base64.h
|
||||
src/misc/endianness.h
|
||||
src/misc/cast.h
|
||||
src/misc/rnd.h
|
||||
src/misc/time.h
|
||||
src/misc/std_unique_ptr.h
|
||||
src/misc/net.h
|
||||
src/misc/lambda.h
|
||||
src/misc/hex.h
|
||||
src/misc/advanced_mutex.h
|
||||
src/misc/memtracker.h
|
||||
src/misc/strobf.h
|
||||
|
||||
src/log/translation.h
|
||||
src/log/LogUtils.h
|
||||
|
||||
src/PermissionManager.h
|
||||
src/protocol/buffers.h
|
||||
src/protocol/Packet.h
|
||||
src/Properties.h
|
||||
src/BasicChannel.h
|
||||
src/Definitions.h
|
||||
src/Error.h
|
||||
src/protocol/CryptHandler.h
|
||||
src/Variable.h
|
||||
src/misc/queue.h
|
||||
|
||||
src/misc/digest.h
|
||||
|
||||
src/bbcode/bbcodes.h
|
||||
|
||||
src/channel/TreeView.h
|
||||
)
|
||||
|
||||
if(HAVE_SQLITE3)
|
||||
set(SOURCE_FILES ${SOURCE_FILES}
|
||||
src/sql/SqlQuery.cpp
|
||||
src/sql/sqlite/SqliteSQL.cpp
|
||||
src/sql/mysql/MySQL.cpp
|
||||
)
|
||||
set(HEADER_FILES ${HEADER_FILES}
|
||||
src/sql/SqlQuery.h
|
||||
src/sql/sqlite/SqliteSQL.h
|
||||
src/sql/mysql/MySQL.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(HAVE_OPEN_SSL)
|
||||
set(SOURCE_FILES ${SOURCE_FILES}
|
||||
src/ssl/SSLManager.cpp
|
||||
)
|
||||
set(HEADER_FILES ${HEADER_FILES}
|
||||
src/ssl/SSLManager.h
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(TeaSpeak STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
target_link_libraries(TeaSpeak PUBLIC threadpool::static jsoncpp_lib)
|
||||
target_compile_options(TeaSpeak PRIVATE "-Wall")
|
||||
|
||||
if (TEASPEAK_SERVER)
|
||||
target_link_libraries(TeaSpeak PUBLIC CXXTerminal::static)
|
||||
endif ()
|
||||
target_include_directories(TeaSpeak PUBLIC src/)
|
||||
install(TARGETS TeaSpeak
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
INSTALL (
|
||||
DIRECTORY ${CMAKE_SOURCE_DIR}/src/
|
||||
DESTINATION include
|
||||
FILES_MATCHING PATTERN "*.h*"
|
||||
)
|
||||
|
||||
set(TEST_LIBRARIES
|
||||
threadpool::static #Static
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
CXXTerminal::static #Static
|
||||
${StringVariable_LIBRARIES_STATIC}
|
||||
${YAML_CPP_LIBRARIES}
|
||||
pthread
|
||||
stdc++fs
|
||||
libevent::core libevent::pthreads
|
||||
opus::static
|
||||
yaml-cpp
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
|
||||
breakpad::static
|
||||
protobuf::libprotobuf
|
||||
jemalloc::shared
|
||||
|
||||
tomcrypt::static
|
||||
tommath::static
|
||||
|
||||
mysqlclient.a
|
||||
jsoncpp_lib
|
||||
${ed25519_LIBRARIES_STATIC}
|
||||
${DataPipes_LIBRARIES_SHARED} # Also includes glib2.0
|
||||
|
||||
openssl::ssl::shared
|
||||
openssl::crypto::shared
|
||||
dl
|
||||
z
|
||||
)
|
||||
include_directories(src/)
|
||||
option(BUILD_TESTS "Enable/disable test building" ON)
|
||||
if(BUILD_TESTS)
|
||||
add_executable(RingTest test/RingTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(RingTest ${TEST_LIBRARIES})
|
||||
|
||||
if(NOT WIN32)
|
||||
add_executable(CommandTest ${SOURCE_FILES} ${HEADER_FILES} test/CommandTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h ../server/MySQLLibSSLFix.c)
|
||||
target_link_libraries(CommandTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(WebsocketTest ${SOURCE_FILES} ${HEADER_FILES} test/WSSTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(WebsocketTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(SQLTest ${SOURCE_FILES} ${HEADER_FILES} test/SQLTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(SQLTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(ChannelTest ${SOURCE_FILES} ${HEADER_FILES} test/ChannelTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(ChannelTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(EndianessTest ${SOURCE_FILES} ${HEADER_FILES} test/EndianessTest.cpp src/log/LogSinks.cpp src/log/LogSinks.h)
|
||||
target_link_libraries(EndianessTest ${TEST_LIBRARIES})
|
||||
|
||||
include_directories(/usr/local/include/breakpad)
|
||||
add_executable(CrashTest test/CrashTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(CrashTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(PorpertyTest test/PropertyTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(PorpertyTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES} src/query/command_unused.h)
|
||||
target_link_libraries(BBTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(LinkedTest test/LinkedTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(LinkedTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(PermissionTest test/PermissionTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(PermissionTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(GenerationTest test/generationTest.cpp ${SOURCE_FILES} ../server/MySQLLibSSLFix.c)
|
||||
target_link_libraries(GenerationTest ${TEST_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
412
src/Error.cpp
412
src/Error.cpp
@ -1,207 +1,207 @@
|
||||
//
|
||||
// Created by wolverindev on 17.10.17.
|
||||
//
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
using namespace ts;
|
||||
|
||||
const std::vector<ErrorType> ts::avariableErrors = {
|
||||
{0x0000, "ok" , "ok" },
|
||||
{0x0001, "undefined" , "undefined error" },
|
||||
{0x0002, "not_implemented" , "not implemented" },
|
||||
{0x0005, "lib_time_limit_reached" , "library time limit reached" },
|
||||
|
||||
{0x0100, "command_not_found" , "command not found" },
|
||||
{0x0101, "unable_to_bind_network_port" , "unable to bind network port" },
|
||||
{0x0102, "no_network_port_available" , "no network port available" },
|
||||
|
||||
{0x0200, "client_invalid_id" , "invalid clientID" },
|
||||
{0x0201, "client_nickname_inuse" , "nickname is already in use" },
|
||||
{0x0202, "" , "invalid error code" },
|
||||
{0x0203, "client_protocol_limit_reached" , "max clients protocol limit reached" },
|
||||
{0x0204, "client_invalid_type" , "invalid client type" },
|
||||
{0x0205, "client_already_subscribed" , "already subscribed" },
|
||||
{0x0206, "client_not_logged_in" , "not logged in" },
|
||||
{0x0207, "client_could_not_validate_identity" , "could not validate client identity" },
|
||||
{0x0208, "client_invalid_password" , "invalid loginname or password" },
|
||||
{0x0209, "client_too_many_clones_connected" , "too many clones already connected" },
|
||||
{0x020A, "client_version_outdated" , "client version outdated, please update" },
|
||||
{0x020B, "client_is_online" , "client is online" },
|
||||
{0x020C, "client_is_flooding" , "client is flooding" },
|
||||
{0x020D, "client_hacked" , "client is modified" },
|
||||
{0x020E, "client_cannot_verify_now" , "can not verify client at this moment" },
|
||||
{0x020F, "client_login_not_permitted" , "client is not permitted to log in" },
|
||||
{0x0210, "client_not_subscribed" , "client is not subscribed to the channel" },
|
||||
{0x0211, "client_unknown" , "client is not known" },
|
||||
{0x0212, "client_join_rate_limit_reached" , "client has reached his join attempt limit" },
|
||||
{0x0213, "client_is_already_member_of_group" , "client is already a member of the group" },
|
||||
{0x0214, "client_is_not_member_of_group" , "client is not a member of the group" },
|
||||
{0x0215, "client_type_is_not_allowed" , "client type is not allowed to join the server" },
|
||||
|
||||
{0x0300, "channel_invalid_id" , "invalid channelID" },
|
||||
{0x0301, "channel_protocol_limit_reached" , "max channels protocol limit reached" },
|
||||
{0x0302, "channel_already_in" , "already member of channel" },
|
||||
{0x0303, "channel_name_inuse" , "channel name is already in use" },
|
||||
{0x0304, "channel_not_empty" , "channel not empty" },
|
||||
{0x0305, "channel_can_not_delete_default" , "can not delete default channel" },
|
||||
{0x0306, "channel_default_require_permanent" , "default channel requires permanent" },
|
||||
{0x0307, "channel_invalid_flags" , "invalid channel flags" },
|
||||
{0x0308, "channel_parent_not_permanent" , "permanent channel can not be child of non permanent channel"},
|
||||
{0x0309, "channel_maxclients_reached" , "channel maxclient reached" },
|
||||
{0x030A, "channel_maxfamily_reached" , "channel maxfamily reached" },
|
||||
{0x030B, "channel_invalid_order" , "invalid channel order" },
|
||||
{0x030C, "channel_no_filetransfer_supported" , "channel does not support filetransfers" },
|
||||
{0x030D, "channel_invalid_password" , "invalid channel password" },
|
||||
{0x030E, "channel_is_private_channel" , "channel is private channel" },
|
||||
{0x030F, "channel_invalid_security_hash" , "invalid security hash supplied by client" },
|
||||
{0x0310, "channel_is_deleted" , "target channel is deleted" },
|
||||
{0x0311, "channel_name_invalid" , "channel name is invalid" },
|
||||
{0x0312, "channel_limit_reached" , "the virtualserver channel limit has been reached" },
|
||||
|
||||
{0x0400, "server_invalid_id" , "invalid serverID" },
|
||||
{0x0401, "server_running" , "server is running" },
|
||||
{0x0402, "server_is_shutting_down" , "server is shutting down" },
|
||||
{0x0403, "server_maxclients_reached" , "server maxclient reached" },
|
||||
{0x0404, "server_invalid_password" , "invalid server password" },
|
||||
{0x0405, "server_deployment_active" , "deployment active" },
|
||||
{0x0406, "server_unable_to_stop_own_server" , "unable to stop own server in your connection class" },
|
||||
{0x0407, "server_is_virtual" , "server is virtual" },
|
||||
{0x0408, "server_wrong_machineid" , "server wrong machineID" },
|
||||
{0x0409, "server_is_not_running" , "server is not running" },
|
||||
{0x040A, "server_is_booting" , "server is booting up" },
|
||||
{0x040B, "server_status_invalid" , "server got an invalid status for this operation" },
|
||||
{0x040C, "server_modal_quit" , "server modal quit" },
|
||||
{0x040D, "server_version_outdated" , "server version is too old for command" },
|
||||
{0x040D, "server_already_joined" , "query client already joined to the server" },
|
||||
{0x040E, "server_is_not_shutting_down" , "server isn't shutting down" },
|
||||
{0x040F, "server_max_vs_reached" , "You reached the maximal virtual server limit" },
|
||||
{0x0410, "server_unbound" , "you are not bound to any server" },
|
||||
{0x0411, "server_join_rate_limit_reached" , "the server reached his join attempt limit" },
|
||||
|
||||
|
||||
{0x0500, "sql" , "sql error" },
|
||||
{0x0501, "database_empty_result" , "sql empty result set" },
|
||||
{0x0502, "database_duplicate_entry" , "sql duplicate entry" },
|
||||
{0x0503, "database_no_modifications" , "sql no modifications" },
|
||||
{0x0504, "database_constraint" , "sql invalid constraint" },
|
||||
{0x0505, "database_reinvoke" , "sql reinvoke command" },
|
||||
|
||||
{0x0600, "parameter_quote" , "invalid quote" },
|
||||
{0x0601, "parameter_invalid_count" , "invalid parameter count" },
|
||||
{0x0602, "parameter_invalid" , "invalid parameter" },
|
||||
{0x0603, "parameter_not_found" , "parameter not found" },
|
||||
{0x0604, "parameter_convert" , "convert error" },
|
||||
{0x0605, "parameter_invalid_size" , "invalid parameter size" },
|
||||
{0x0606, "parameter_missing" , "missing required parameter" },
|
||||
{0x0607, "parameter_checksum" , "invalid checksum" },
|
||||
|
||||
{0x0700, "vs_critical" , "virtual server got a critical error" },
|
||||
{0x0701, "connection_lost" , "Connection lost" },
|
||||
{0x0702, "not_connected" , "not connected" },
|
||||
{0x0703, "no_cached_connection_info" , "no cached connection info" },
|
||||
{0x0704, "currently_not_possible" , "currently not possible" },
|
||||
{0x0705, "failed_connection_initialisation" , "failed connection initialization" },
|
||||
{0x0706, "could_not_resolve_hostname" , "could not resolve hostname" },
|
||||
{0x0707, "invalid_server_connection_handler_id" , "invalid server connection handler ID" },
|
||||
{0x0708, "could_not_initialise_input_client" , "could not initialize Input client" },
|
||||
{0x0709, "clientlibrary_not_initialised" , "client library not initialized" },
|
||||
{0x070A, "serverlibrary_not_initialised" , "server library not initialized" },
|
||||
{0x070B, "whisper_too_many_targets" , "too many whisper targets" },
|
||||
{0x070C, "whisper_no_targets" , "no whisper targets found" },
|
||||
|
||||
{0x0800, "file_invalid_name" , "invalid file name" },
|
||||
{0x0801, "file_invalid_permissions" , "invalid file permissions" },
|
||||
{0x0802, "file_already_exists" , "file already exists" },
|
||||
{0x0803, "file_not_found" , "file not found" },
|
||||
{0x0804, "file_io_error" , "file input/output error" },
|
||||
{0x0805, "file_invalid_transfer_id" , "invalid file transfer ID" },
|
||||
{0x0806, "file_invalid_path" , "invalid file path" },
|
||||
{0x0807, "file_no_files_available" , "no files available" },
|
||||
{0x0808, "file_overwrite_excludes_resume" , "overwrite excludes resume" },
|
||||
{0x0809, "file_invalid_size" , "invalid file size" },
|
||||
{0x080A, "file_already_in_use" , "file already in use" },
|
||||
{0x080B, "file_could_not_open_connection" , "could not open file transfer connection" },
|
||||
{0x080C, "file_no_space_left_on_device" , "no space left on device (disk full?)" },
|
||||
{0x080D, "file_exceeds_file_system_maximum_size", "file exceeds file system's maximum file size" },
|
||||
{0x080E, "file_transfer_connection_timeout" , "file transfer connection timeout" },
|
||||
{0x080F, "file_connection_lost" , "lost file transfer connection" },
|
||||
{0x0810, "file_exceeds_supplied_size" , "file exceeds supplied file size" },
|
||||
{0x0811, "file_transfer_complete" , "file transfer complete" },
|
||||
{0x0812, "file_transfer_canceled" , "file transfer canceled" },
|
||||
{0x0813, "file_transfer_interrupted" , "file transfer interrupted" },
|
||||
{0x0814, "file_transfer_server_quota_exceeded" , "file transfer server quota exceeded" },
|
||||
{0x0815, "file_transfer_client_quota_exceeded" , "file transfer client quota exceeded" },
|
||||
{0x0816, "file_transfer_reset" , "file transfer reset" },
|
||||
{0x0817, "file_transfer_limit_reached" , "file transfer limit reached" },
|
||||
|
||||
|
||||
{0x0A08, "server_insufficeient_permissions" , "insufficient client permissions" },
|
||||
|
||||
{0x0B01, "accounting_slot_limit_reached" , "max slot limit reached" },
|
||||
|
||||
{0x0D01, "server_connect_banned" , "connection failed, you are banned" },
|
||||
{0x0D03, "ban_flooding" , "flood ban" },
|
||||
|
||||
{0x0F00, "token_invalid_id" , "invalid privilege key" },
|
||||
|
||||
{0x1001, "web_handshake_invalid" , "Invalid handshake" },
|
||||
{0x1001, "web_handshake_unsupported" , "Handshake intention unsupported" },
|
||||
{0x1002, "web_handshake_identity_unsupported" , "Handshake identity unsupported" },
|
||||
{0x1003, "web_handshake_identity_proof_failed" , "Identity proof failed" },
|
||||
{0x1004, "web_handshake_identity_outdated" , "data seems to be outdated" },
|
||||
|
||||
{0x1100, "music_invalid_id" , "invalid botID" },
|
||||
{0x1101, "music_limit_reached" , "Server music bot limit is reached" },
|
||||
{0x1102, "music_client_limit_reached" , "Client music bot limit is reached" },
|
||||
{0x1103, "music_invalid_player_state" , "Invalid player state" },
|
||||
{0x1104, "music_invalid_action" , "Invalid action" },
|
||||
{0x1105, "music_no_player" , "Missing player instance" },
|
||||
{0x1105, "music_disabled" , "Music bots have been disabled" },
|
||||
|
||||
{0x2100, "playlist_invalid_id" , "invalid playlist id" },
|
||||
{0x2101, "playlist_invalid_song_id" , "invalid playlist song id" },
|
||||
{0x2102, "playlist_already_in_use" , "playlist is already used by another bot" },
|
||||
{0x2103, "playlist_is_in_use" , "playlist is used by another bot" },
|
||||
|
||||
{0x2200, "conversation_invalid_id" , "invalid conversation id" },
|
||||
{0x2201, "conversation_more_data" , "there are more messages to send" },
|
||||
{0x2202, "conversation_is_private" , "the target conversation is private" },
|
||||
|
||||
{0x1200, "query_not_exists" , "query account does not exists" },
|
||||
{0x1201, "query_already_exists" , "query account already exists" },
|
||||
{0x1202, "query_too_many_simultaneously_sessions", "too many simultaneously connected sessions" },
|
||||
{0x1203, "query_maxclients_reached" , "query server reached its limit" },
|
||||
|
||||
{0x1300, "group_invalid_id" , "Invalid group id" },
|
||||
{0x1301, "group_name_inuse" , "Group name is already in use" },
|
||||
{0x1302, "group_not_assigned_over_this_server" , "the group hasn't been assigned over this server" },
|
||||
|
||||
{0xE000, "resource_limit_reached" , "resource limit reached" },
|
||||
|
||||
{0xFFFF, "custom_error" , "costume" },
|
||||
};
|
||||
ErrorType ErrorType::Success = avariableErrors[0];
|
||||
ErrorType ErrorType::Costume = findError("custom_error");
|
||||
ErrorType ErrorType::VSError = findError("vs_critical");
|
||||
ErrorType ErrorType::DBEmpty = findError("database_empty_result");
|
||||
|
||||
ErrorType ts::findError(uint16_t errorId){
|
||||
for(auto elm : avariableErrors)
|
||||
if(elm.errorId == errorId) return elm;
|
||||
return ErrorType{errorId, "undefined", "undefined"};
|
||||
}
|
||||
|
||||
ErrorType ts::findError(std::string key){
|
||||
for(auto elm : avariableErrors)
|
||||
if(elm.name == key) return elm;
|
||||
return ErrorType{1, key, "undefined"};
|
||||
}
|
||||
|
||||
CommandResult CommandResult::Success = {avariableErrors[0], ""};
|
||||
CommandResult CommandResult::NotImplemented = {avariableErrors[2], ""};
|
||||
|
||||
CommandResultPermissionError::CommandResultPermissionError(permission::PermissionType error, const std::string &extraMsg) : CommandResult(findError(0x0A08), "") {
|
||||
this->extraProperties["failed_permid"] = std::to_string((int16_t) error);
|
||||
this->_type = PERM_ERROR;
|
||||
//
|
||||
// Created by wolverindev on 17.10.17.
|
||||
//
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
using namespace ts;
|
||||
|
||||
const std::vector<ErrorType> ts::avariableErrors = {
|
||||
{0x0000, "ok" , "ok" },
|
||||
{0x0001, "undefined" , "undefined error" },
|
||||
{0x0002, "not_implemented" , "not implemented" },
|
||||
{0x0005, "lib_time_limit_reached" , "library time limit reached" },
|
||||
|
||||
{0x0100, "command_not_found" , "command not found" },
|
||||
{0x0101, "unable_to_bind_network_port" , "unable to bind network port" },
|
||||
{0x0102, "no_network_port_available" , "no network port available" },
|
||||
|
||||
{0x0200, "client_invalid_id" , "invalid clientID" },
|
||||
{0x0201, "client_nickname_inuse" , "nickname is already in use" },
|
||||
{0x0202, "" , "invalid error code" },
|
||||
{0x0203, "client_protocol_limit_reached" , "max clients protocol limit reached" },
|
||||
{0x0204, "client_invalid_type" , "invalid client type" },
|
||||
{0x0205, "client_already_subscribed" , "already subscribed" },
|
||||
{0x0206, "client_not_logged_in" , "not logged in" },
|
||||
{0x0207, "client_could_not_validate_identity" , "could not validate client identity" },
|
||||
{0x0208, "client_invalid_password" , "invalid loginname or password" },
|
||||
{0x0209, "client_too_many_clones_connected" , "too many clones already connected" },
|
||||
{0x020A, "client_version_outdated" , "client version outdated, please update" },
|
||||
{0x020B, "client_is_online" , "client is online" },
|
||||
{0x020C, "client_is_flooding" , "client is flooding" },
|
||||
{0x020D, "client_hacked" , "client is modified" },
|
||||
{0x020E, "client_cannot_verify_now" , "can not verify client at this moment" },
|
||||
{0x020F, "client_login_not_permitted" , "client is not permitted to log in" },
|
||||
{0x0210, "client_not_subscribed" , "client is not subscribed to the channel" },
|
||||
{0x0211, "client_unknown" , "client is not known" },
|
||||
{0x0212, "client_join_rate_limit_reached" , "client has reached his join attempt limit" },
|
||||
{0x0213, "client_is_already_member_of_group" , "client is already a member of the group" },
|
||||
{0x0214, "client_is_not_member_of_group" , "client is not a member of the group" },
|
||||
{0x0215, "client_type_is_not_allowed" , "client type is not allowed to join the server" },
|
||||
|
||||
{0x0300, "channel_invalid_id" , "invalid channelID" },
|
||||
{0x0301, "channel_protocol_limit_reached" , "max channels protocol limit reached" },
|
||||
{0x0302, "channel_already_in" , "already member of channel" },
|
||||
{0x0303, "channel_name_inuse" , "channel name is already in use" },
|
||||
{0x0304, "channel_not_empty" , "channel not empty" },
|
||||
{0x0305, "channel_can_not_delete_default" , "can not delete default channel" },
|
||||
{0x0306, "channel_default_require_permanent" , "default channel requires permanent" },
|
||||
{0x0307, "channel_invalid_flags" , "invalid channel flags" },
|
||||
{0x0308, "channel_parent_not_permanent" , "permanent channel can not be child of non permanent channel"},
|
||||
{0x0309, "channel_maxclients_reached" , "channel maxclient reached" },
|
||||
{0x030A, "channel_maxfamily_reached" , "channel maxfamily reached" },
|
||||
{0x030B, "channel_invalid_order" , "invalid channel order" },
|
||||
{0x030C, "channel_no_filetransfer_supported" , "channel does not support filetransfers" },
|
||||
{0x030D, "channel_invalid_password" , "invalid channel password" },
|
||||
{0x030E, "channel_is_private_channel" , "channel is private channel" },
|
||||
{0x030F, "channel_invalid_security_hash" , "invalid security hash supplied by client" },
|
||||
{0x0310, "channel_is_deleted" , "target channel is deleted" },
|
||||
{0x0311, "channel_name_invalid" , "channel name is invalid" },
|
||||
{0x0312, "channel_limit_reached" , "the virtualserver channel limit has been reached" },
|
||||
|
||||
{0x0400, "server_invalid_id" , "invalid serverID" },
|
||||
{0x0401, "server_running" , "server is running" },
|
||||
{0x0402, "server_is_shutting_down" , "server is shutting down" },
|
||||
{0x0403, "server_maxclients_reached" , "server maxclient reached" },
|
||||
{0x0404, "server_invalid_password" , "invalid server password" },
|
||||
{0x0405, "server_deployment_active" , "deployment active" },
|
||||
{0x0406, "server_unable_to_stop_own_server" , "unable to stop own server in your connection class" },
|
||||
{0x0407, "server_is_virtual" , "server is virtual" },
|
||||
{0x0408, "server_wrong_machineid" , "server wrong machineID" },
|
||||
{0x0409, "server_is_not_running" , "server is not running" },
|
||||
{0x040A, "server_is_booting" , "server is booting up" },
|
||||
{0x040B, "server_status_invalid" , "server got an invalid status for this operation" },
|
||||
{0x040C, "server_modal_quit" , "server modal quit" },
|
||||
{0x040D, "server_version_outdated" , "server version is too old for command" },
|
||||
{0x040D, "server_already_joined" , "query client already joined to the server" },
|
||||
{0x040E, "server_is_not_shutting_down" , "server isn't shutting down" },
|
||||
{0x040F, "server_max_vs_reached" , "You reached the maximal virtual server limit" },
|
||||
{0x0410, "server_unbound" , "you are not bound to any server" },
|
||||
{0x0411, "server_join_rate_limit_reached" , "the server reached his join attempt limit" },
|
||||
|
||||
|
||||
{0x0500, "sql" , "sql error" },
|
||||
{0x0501, "database_empty_result" , "sql empty result set" },
|
||||
{0x0502, "database_duplicate_entry" , "sql duplicate entry" },
|
||||
{0x0503, "database_no_modifications" , "sql no modifications" },
|
||||
{0x0504, "database_constraint" , "sql invalid constraint" },
|
||||
{0x0505, "database_reinvoke" , "sql reinvoke command" },
|
||||
|
||||
{0x0600, "parameter_quote" , "invalid quote" },
|
||||
{0x0601, "parameter_invalid_count" , "invalid parameter count" },
|
||||
{0x0602, "parameter_invalid" , "invalid parameter" },
|
||||
{0x0603, "parameter_not_found" , "parameter not found" },
|
||||
{0x0604, "parameter_convert" , "convert error" },
|
||||
{0x0605, "parameter_invalid_size" , "invalid parameter size" },
|
||||
{0x0606, "parameter_missing" , "missing required parameter" },
|
||||
{0x0607, "parameter_checksum" , "invalid checksum" },
|
||||
|
||||
{0x0700, "vs_critical" , "virtual server got a critical error" },
|
||||
{0x0701, "connection_lost" , "Connection lost" },
|
||||
{0x0702, "not_connected" , "not connected" },
|
||||
{0x0703, "no_cached_connection_info" , "no cached connection info" },
|
||||
{0x0704, "currently_not_possible" , "currently not possible" },
|
||||
{0x0705, "failed_connection_initialisation" , "failed connection initialization" },
|
||||
{0x0706, "could_not_resolve_hostname" , "could not resolve hostname" },
|
||||
{0x0707, "invalid_server_connection_handler_id" , "invalid server connection handler ID" },
|
||||
{0x0708, "could_not_initialise_input_client" , "could not initialize Input client" },
|
||||
{0x0709, "clientlibrary_not_initialised" , "client library not initialized" },
|
||||
{0x070A, "serverlibrary_not_initialised" , "server library not initialized" },
|
||||
{0x070B, "whisper_too_many_targets" , "too many whisper targets" },
|
||||
{0x070C, "whisper_no_targets" , "no whisper targets found" },
|
||||
|
||||
{0x0800, "file_invalid_name" , "invalid file name" },
|
||||
{0x0801, "file_invalid_permissions" , "invalid file permissions" },
|
||||
{0x0802, "file_already_exists" , "file already exists" },
|
||||
{0x0803, "file_not_found" , "file not found" },
|
||||
{0x0804, "file_io_error" , "file input/output error" },
|
||||
{0x0805, "file_invalid_transfer_id" , "invalid file transfer ID" },
|
||||
{0x0806, "file_invalid_path" , "invalid file path" },
|
||||
{0x0807, "file_no_files_available" , "no files available" },
|
||||
{0x0808, "file_overwrite_excludes_resume" , "overwrite excludes resume" },
|
||||
{0x0809, "file_invalid_size" , "invalid file size" },
|
||||
{0x080A, "file_already_in_use" , "file already in use" },
|
||||
{0x080B, "file_could_not_open_connection" , "could not open file transfer connection" },
|
||||
{0x080C, "file_no_space_left_on_device" , "no space left on device (disk full?)" },
|
||||
{0x080D, "file_exceeds_file_system_maximum_size", "file exceeds file system's maximum file size" },
|
||||
{0x080E, "file_transfer_connection_timeout" , "file transfer connection timeout" },
|
||||
{0x080F, "file_connection_lost" , "lost file transfer connection" },
|
||||
{0x0810, "file_exceeds_supplied_size" , "file exceeds supplied file size" },
|
||||
{0x0811, "file_transfer_complete" , "file transfer complete" },
|
||||
{0x0812, "file_transfer_canceled" , "file transfer canceled" },
|
||||
{0x0813, "file_transfer_interrupted" , "file transfer interrupted" },
|
||||
{0x0814, "file_transfer_server_quota_exceeded" , "file transfer server quota exceeded" },
|
||||
{0x0815, "file_transfer_client_quota_exceeded" , "file transfer client quota exceeded" },
|
||||
{0x0816, "file_transfer_reset" , "file transfer reset" },
|
||||
{0x0817, "file_transfer_limit_reached" , "file transfer limit reached" },
|
||||
|
||||
|
||||
{0x0A08, "server_insufficeient_permissions" , "insufficient client permissions" },
|
||||
|
||||
{0x0B01, "accounting_slot_limit_reached" , "max slot limit reached" },
|
||||
|
||||
{0x0D01, "server_connect_banned" , "connection failed, you are banned" },
|
||||
{0x0D03, "ban_flooding" , "flood ban" },
|
||||
|
||||
{0x0F00, "token_invalid_id" , "invalid privilege key" },
|
||||
|
||||
{0x1001, "web_handshake_invalid" , "Invalid handshake" },
|
||||
{0x1001, "web_handshake_unsupported" , "Handshake intention unsupported" },
|
||||
{0x1002, "web_handshake_identity_unsupported" , "Handshake identity unsupported" },
|
||||
{0x1003, "web_handshake_identity_proof_failed" , "Identity proof failed" },
|
||||
{0x1004, "web_handshake_identity_outdated" , "data seems to be outdated" },
|
||||
|
||||
{0x1100, "music_invalid_id" , "invalid botID" },
|
||||
{0x1101, "music_limit_reached" , "Server music bot limit is reached" },
|
||||
{0x1102, "music_client_limit_reached" , "Client music bot limit is reached" },
|
||||
{0x1103, "music_invalid_player_state" , "Invalid player state" },
|
||||
{0x1104, "music_invalid_action" , "Invalid action" },
|
||||
{0x1105, "music_no_player" , "Missing player instance" },
|
||||
{0x1105, "music_disabled" , "Music bots have been disabled" },
|
||||
|
||||
{0x2100, "playlist_invalid_id" , "invalid playlist id" },
|
||||
{0x2101, "playlist_invalid_song_id" , "invalid playlist song id" },
|
||||
{0x2102, "playlist_already_in_use" , "playlist is already used by another bot" },
|
||||
{0x2103, "playlist_is_in_use" , "playlist is used by another bot" },
|
||||
|
||||
{0x2200, "conversation_invalid_id" , "invalid conversation id" },
|
||||
{0x2201, "conversation_more_data" , "there are more messages to send" },
|
||||
{0x2202, "conversation_is_private" , "the target conversation is private" },
|
||||
|
||||
{0x1200, "query_not_exists" , "query account does not exists" },
|
||||
{0x1201, "query_already_exists" , "query account already exists" },
|
||||
{0x1202, "query_too_many_simultaneously_sessions", "too many simultaneously connected sessions" },
|
||||
{0x1203, "query_maxclients_reached" , "query server reached its limit" },
|
||||
|
||||
{0x1300, "group_invalid_id" , "Invalid group id" },
|
||||
{0x1301, "group_name_inuse" , "Group name is already in use" },
|
||||
{0x1302, "group_not_assigned_over_this_server" , "the group hasn't been assigned over this server" },
|
||||
|
||||
{0xE000, "resource_limit_reached" , "resource limit reached" },
|
||||
|
||||
{0xFFFF, "custom_error" , "costume" },
|
||||
};
|
||||
ErrorType ErrorType::Success = avariableErrors[0];
|
||||
ErrorType ErrorType::Costume = findError("custom_error");
|
||||
ErrorType ErrorType::VSError = findError("vs_critical");
|
||||
ErrorType ErrorType::DBEmpty = findError("database_empty_result");
|
||||
|
||||
ErrorType ts::findError(uint16_t errorId){
|
||||
for(auto elm : avariableErrors)
|
||||
if(elm.errorId == errorId) return elm;
|
||||
return ErrorType{errorId, "undefined", "undefined"};
|
||||
}
|
||||
|
||||
ErrorType ts::findError(std::string key){
|
||||
for(auto elm : avariableErrors)
|
||||
if(elm.name == key) return elm;
|
||||
return ErrorType{1, key, "undefined"};
|
||||
}
|
||||
|
||||
CommandResult CommandResult::Success = {avariableErrors[0], ""};
|
||||
CommandResult CommandResult::NotImplemented = {avariableErrors[2], ""};
|
||||
|
||||
CommandResultPermissionError::CommandResultPermissionError(permission::PermissionType error, const std::string &extraMsg) : CommandResult(findError(0x0A08), "") {
|
||||
this->extraProperties["failed_permid"] = std::to_string((int16_t) error);
|
||||
this->_type = PERM_ERROR;
|
||||
}
|
790
src/Error.h
790
src/Error.h
@ -1,396 +1,396 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#define _NDEBUG
|
||||
|
||||
namespace ts {
|
||||
struct CommandResult;
|
||||
namespace permission {
|
||||
enum PermissionType : uint16_t;
|
||||
}
|
||||
|
||||
struct error {
|
||||
enum type : uint16_t {
|
||||
ok = 0x0,
|
||||
undefined = 0x1,
|
||||
not_implemented = 0x2,
|
||||
lib_time_limit_reached = 0x5,
|
||||
command_not_found = 0x100,
|
||||
unable_to_bind_network_port = 0x101,
|
||||
no_network_port_available = 0x102,
|
||||
client_invalid_id = 0x200,
|
||||
client_nickname_inuse = 0x201,
|
||||
invalid_error_code = 0x202,
|
||||
|
||||
client_protocol_limit_reached = 0x203,
|
||||
client_invalid_type = 0x204,
|
||||
client_already_subscribed = 0x205,
|
||||
client_not_logged_in = 0x206,
|
||||
client_could_not_validate_identity = 0x207,
|
||||
client_invalid_password = 0x208,
|
||||
client_too_many_clones_connected = 0x209,
|
||||
client_version_outdated = 0x20a,
|
||||
client_is_online = 0x20b,
|
||||
client_is_flooding = 0x20c,
|
||||
client_hacked = 0x20d,
|
||||
client_cannot_verify_now = 0x20e,
|
||||
client_login_not_permitted = 0x20f,
|
||||
client_not_subscribed = 0x210,
|
||||
client_unknown = 0x0211,
|
||||
client_join_rate_limit_reached = 0x0212,
|
||||
client_is_already_member_of_group = 0x0213,
|
||||
client_is_not_member_of_group = 0x0214,
|
||||
client_type_is_not_allowed = 0x0215,
|
||||
|
||||
channel_invalid_id = 0x300,
|
||||
channel_protocol_limit_reached = 0x301,
|
||||
channel_already_in = 0x302,
|
||||
channel_name_inuse = 0x303,
|
||||
channel_not_empty = 0x304,
|
||||
channel_can_not_delete_default = 0x305,
|
||||
channel_default_require_permanent = 0x306,
|
||||
channel_invalid_flags = 0x307,
|
||||
channel_parent_not_permanent = 0x308,
|
||||
channel_maxclients_reached = 0x309,
|
||||
channel_maxfamily_reached = 0x30a,
|
||||
channel_invalid_order = 0x30b,
|
||||
channel_no_filetransfer_supported = 0x30c,
|
||||
channel_invalid_password = 0x30d,
|
||||
channel_is_private_channel = 0x30e,
|
||||
channel_invalid_security_hash = 0x30f,
|
||||
channel_is_deleted = 0x310,
|
||||
channel_name_invalid = 0x311,
|
||||
channel_limit_reached = 0x312,
|
||||
|
||||
server_invalid_id = 0x400,
|
||||
server_running = 0x401,
|
||||
server_is_shutting_down = 0x402,
|
||||
server_maxclients_reached = 0x403,
|
||||
server_invalid_password = 0x404,
|
||||
server_deployment_active = 0x405,
|
||||
server_unable_to_stop_own_server = 0x406,
|
||||
server_is_virtual = 0x407,
|
||||
server_wrong_machineid = 0x408,
|
||||
server_is_not_running = 0x409,
|
||||
server_is_booting = 0x40a,
|
||||
server_status_invalid = 0x40b,
|
||||
server_modal_quit = 0x40c,
|
||||
server_version_outdated = 0x40d,
|
||||
server_already_joined = 0x40d,
|
||||
server_is_not_shutting_down = 0x40e,
|
||||
server_max_vs_reached = 0x40f,
|
||||
server_unbound = 0x410,
|
||||
server_join_rate_limit_reached = 0x411,
|
||||
|
||||
sql = 0x500,
|
||||
database_empty_result = 0x501,
|
||||
database_duplicate_entry = 0x502,
|
||||
database_no_modifications = 0x503,
|
||||
database_constraint = 0x504,
|
||||
database_reinvoke = 0x505,
|
||||
parameter_quote = 0x600,
|
||||
parameter_invalid_count = 0x601,
|
||||
parameter_invalid = 0x602,
|
||||
parameter_not_found = 0x603,
|
||||
parameter_convert = 0x604,
|
||||
parameter_invalid_size = 0x605,
|
||||
parameter_missing = 0x606,
|
||||
parameter_checksum = 0x607,
|
||||
vs_critical = 0x700,
|
||||
connection_lost = 0x701,
|
||||
not_connected = 0x702,
|
||||
no_cached_connection_info = 0x703,
|
||||
currently_not_possible = 0x704,
|
||||
failed_connection_initialisation = 0x705,
|
||||
could_not_resolve_hostname = 0x706,
|
||||
invalid_server_connection_handler_id = 0x707,
|
||||
could_not_initialise_input_client = 0x708,
|
||||
clientlibrary_not_initialised = 0x709,
|
||||
serverlibrary_not_initialised = 0x70a,
|
||||
whisper_too_many_targets = 0x70b,
|
||||
whisper_no_targets = 0x70c,
|
||||
file_invalid_name = 0x800,
|
||||
file_invalid_permissions = 0x801,
|
||||
file_already_exists = 0x802,
|
||||
file_not_found = 0x803,
|
||||
file_io_error = 0x804,
|
||||
file_invalid_transfer_id = 0x805,
|
||||
file_invalid_path = 0x806,
|
||||
file_no_files_available = 0x807,
|
||||
file_overwrite_excludes_resume = 0x808,
|
||||
file_invalid_size = 0x809,
|
||||
file_already_in_use = 0x80a,
|
||||
file_could_not_open_connection = 0x80b,
|
||||
file_no_space_left_on_device = 0x80c,
|
||||
file_exceeds_file_system_maximum_size = 0x80d,
|
||||
file_transfer_connection_timeout = 0x80e,
|
||||
file_connection_lost = 0x80f,
|
||||
file_exceeds_supplied_size = 0x810,
|
||||
file_transfer_complete = 0x811,
|
||||
file_transfer_canceled = 0x812,
|
||||
file_transfer_interrupted = 0x813,
|
||||
file_transfer_server_quota_exceeded = 0x814,
|
||||
file_transfer_client_quota_exceeded = 0x815,
|
||||
file_transfer_reset = 0x816,
|
||||
file_transfer_limit_reached = 0x817,
|
||||
server_insufficeient_permissions = 0xa08,
|
||||
accounting_slot_limit_reached = 0xb01,
|
||||
server_connect_banned = 0xd01,
|
||||
ban_flooding = 0xd03,
|
||||
token_invalid_id = 0xf00,
|
||||
web_handshake_invalid = 0x1001,
|
||||
web_handshake_unsupported = 0x1001,
|
||||
web_handshake_identity_unsupported = 0x1002,
|
||||
web_handshake_identity_proof_failed = 0x1003,
|
||||
web_handshake_identity_outdated = 0x1004,
|
||||
|
||||
music_invalid_id = 0x1100,
|
||||
music_limit_reached = 0x1101,
|
||||
music_client_limit_reached = 0x1102,
|
||||
music_invalid_player_state = 0x1103,
|
||||
music_invalid_action = 0x1104,
|
||||
music_no_player = 0x1105,
|
||||
music_disabled = 0x1105,
|
||||
playlist_invalid_id = 0x2100,
|
||||
playlist_invalid_song_id = 0x2101,
|
||||
playlist_already_in_use = 0x2102,
|
||||
playlist_is_in_use = 0x2103,
|
||||
query_not_exists = 0x1200,
|
||||
query_already_exists = 0x1201,
|
||||
|
||||
group_invalid_id = 0x1300,
|
||||
group_name_inuse = 0x1301,
|
||||
group_not_assigned_over_this_server = 0x1302,
|
||||
|
||||
conversation_invalid_id = 0x2200,
|
||||
conversation_more_data = 0x2201,
|
||||
conversation_is_private = 0x2202,
|
||||
|
||||
custom_error = 0xffff
|
||||
};
|
||||
};
|
||||
|
||||
struct detailed_command_result {
|
||||
error::type error_id;
|
||||
std::map<std::string, std::string> extra_properties;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no destructor!)
|
||||
* return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no destructor!)
|
||||
* return command_result{error::vs_critical, "unknown error"}; => To a lot of code
|
||||
*/
|
||||
struct command_result { /* fixed size of 8 (64 bits) */
|
||||
static constexpr uint64_t MASK_ERROR = ~((uint64_t) 1 << (sizeof(error::type) * 8));
|
||||
static constexpr uint64_t MASK_PERMISSION = ~((uint64_t) 1 << (sizeof(permission::PermissionType) * 8));
|
||||
|
||||
static constexpr uint8_t OFFSET_ERROR = (8 - sizeof(error::type)) * 8;
|
||||
static constexpr uint8_t OFFSET_PERMISSION = (8 - sizeof(permission::PermissionType) - sizeof(error::type)) * 8;
|
||||
/*
|
||||
* First bit is a flag bit which switches between detailed and code mode.
|
||||
* 0 means detailed (Because then we could interpret data as a ptr (all ptr are 8 bit aligned => 3 zero bits))
|
||||
* bits [0;64] => data ptr (needs to be zero at destruction to avoid memory leaks)
|
||||
*
|
||||
* 1 means code
|
||||
* bits [64 - sizeof(error::type);64] => error type | Usually evaluates to [48;64]
|
||||
* bits [64 - sizeof(error::type) - sizeof(permission::PermissionType);64 - sizeof(error::type)] => permission id | Usually evaluates to [32;48]
|
||||
*/
|
||||
uint64_t data = 0;
|
||||
|
||||
/* Test for mode 1 as described before */
|
||||
static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62);
|
||||
|
||||
[[nodiscard]] inline error::type error_code() const {
|
||||
if(this->is_detailed()) return this->details()->error_id;
|
||||
|
||||
return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool is_permission_error() const {
|
||||
return this->error_code() == error::server_insufficeient_permissions;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline permission::PermissionType permission_id() const {
|
||||
if(this->is_detailed()) return (permission::PermissionType) -1; /* not supported */
|
||||
|
||||
return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const detailed_command_result* details() const { return (detailed_command_result*) this->data; }
|
||||
[[nodiscard]] inline detailed_command_result* details() { return (detailed_command_result*) this->data; }
|
||||
|
||||
[[nodiscard]] inline bool is_detailed() const {
|
||||
return (this->data & 0x1UL) == 0;
|
||||
}
|
||||
|
||||
inline std::unique_ptr<detailed_command_result> release_details() {
|
||||
if(!this->is_detailed()) return nullptr;
|
||||
|
||||
auto result = this->details();
|
||||
this->data = 0;
|
||||
return std::unique_ptr<detailed_command_result>{result};
|
||||
}
|
||||
|
||||
/* Attention: Releases the internal detailed pointer! */
|
||||
inline CommandResult as_command_result();
|
||||
|
||||
#ifndef _NDEBUG /* We dont need to secure that because gcc deduct us to an uint64_t and the only advantage is the mem leak test which is deactivated anyways */
|
||||
command_result(command_result&) = delete;
|
||||
command_result(const command_result&) = delete;
|
||||
command_result(command_result&& other) : data(other.data) {
|
||||
other.data = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
command_result() = default;
|
||||
|
||||
explicit command_result(permission::PermissionType permission) {
|
||||
this->data = 0x01; /* the the type to 1 */
|
||||
|
||||
this->data |= (uint64_t) error::server_insufficeient_permissions << OFFSET_ERROR;
|
||||
this->data |= (uint64_t) permission << OFFSET_PERMISSION;
|
||||
}
|
||||
|
||||
|
||||
explicit command_result(error::type error) {
|
||||
this->data = 0x01; /* the the type to 1 */
|
||||
|
||||
this->data |= (uint64_t) error << (8 - sizeof(error::type)) * 8;
|
||||
}
|
||||
|
||||
command_result(error::type error, const std::string& message) {
|
||||
auto details_ptr = new detailed_command_result{};
|
||||
assert(((uintptr_t) details_ptr & 0x03U) == 0); // must be aligned!
|
||||
|
||||
this->data = (uintptr_t) details_ptr;
|
||||
|
||||
details_ptr->error_id = error;
|
||||
details_ptr->extra_properties["extra_msg"] = message;
|
||||
}
|
||||
|
||||
command_result(error::type error, const std::map<std::string, std::string>& properties) : command_result{error, std::string{""}} {
|
||||
assert(this->is_detailed());
|
||||
this->details()->extra_properties = properties;
|
||||
}
|
||||
|
||||
#ifndef _NDEBUG
|
||||
/* if we're not using any debug we dont have to use a deconstructor. A deconstructor prevent a direct uint64_t return as described above */
|
||||
~command_result() {
|
||||
if((this->data & 0x01) == 0x00) {
|
||||
// this->details needs to be removed 'till this gets destructed
|
||||
assert(this->data == 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
static_assert(sizeof(command_result) == 8);
|
||||
|
||||
struct ErrorType {
|
||||
public:
|
||||
static ErrorType Success;
|
||||
static ErrorType Costume;
|
||||
static ErrorType VSError;
|
||||
static ErrorType DBEmpty;
|
||||
|
||||
ErrorType(const uint16_t errorId, std::string name, std::string message) : errorId(errorId), name(std::move(name)), message(std::move(message)) {}
|
||||
ErrorType(const ErrorType& ref) = default;
|
||||
ErrorType(ErrorType&& ref) : errorId(ref.errorId), name(std::move(ref.name)), message(std::move(ref.message)) {}
|
||||
|
||||
uint16_t errorId;
|
||||
std::string name;
|
||||
std::string message;
|
||||
|
||||
bool operator==(const ErrorType& ref) const {
|
||||
return errorId == ref.errorId;
|
||||
}
|
||||
|
||||
bool operator!=(const ErrorType& ref) const { return !operator==(ref); }
|
||||
|
||||
ErrorType& operator=(const ErrorType& ref) {
|
||||
errorId = ref.errorId;
|
||||
name = ref.name;
|
||||
message = ref.message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if fail
|
||||
*/
|
||||
bool operator!() const {
|
||||
return errorId != 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern const std::vector<ErrorType> avariableErrors;
|
||||
extern ErrorType findError(uint16_t errorId);
|
||||
extern ErrorType findError(std::string key);
|
||||
|
||||
enum CommandResultType {
|
||||
GENERAL,
|
||||
PERM_ERROR
|
||||
};
|
||||
|
||||
struct CommandResult {
|
||||
public:
|
||||
static CommandResult Success;
|
||||
static CommandResult NotImplemented;
|
||||
|
||||
CommandResult(const CommandResult& ref) : _type(ref._type), error(ref.error), extraProperties(ref.extraProperties) {}
|
||||
CommandResult(CommandResult&& ref) : _type(ref._type), error(ref.error), extraProperties(ref.extraProperties) {}
|
||||
CommandResult(ErrorType error, const std::string &extraMsg = "") : error(std::move(error)) { if(extraMsg.empty()) return; /*extraProperties["extramsg"] = extraMsg; */extraProperties["extra_msg"] = extraMsg; }
|
||||
CommandResult(std::string error, const std::string &extraMsg = "") : error(findError(std::move(error))) { if(extraMsg.empty()) return; /*extraProperties["extramsg"] = extraMsg; */extraProperties["extra_msg"] = extraMsg; }
|
||||
CommandResult() : CommandResult(ErrorType::Success, ""){}
|
||||
CommandResult(ErrorType error, std::map<std::string, std::string> details) : error(error), extraProperties(std::move(details)) {}
|
||||
|
||||
bool operator==(const CommandResult& ref){
|
||||
return this->error == ref.error && ref.extraProperties == this->extraProperties;
|
||||
}
|
||||
|
||||
CommandResult& operator=(const CommandResult& ref)= default;
|
||||
|
||||
/**
|
||||
* @return true if fail
|
||||
*/
|
||||
bool operator!() const {
|
||||
return this->error != ErrorType::Success;
|
||||
}
|
||||
virtual CommandResultType type(){ return _type; }
|
||||
|
||||
ErrorType error;
|
||||
std::map<std::string, std::string> extraProperties;
|
||||
CommandResultType _type = CommandResultType::GENERAL;
|
||||
};
|
||||
|
||||
struct CommandResultPermissionError : public CommandResult {
|
||||
public:
|
||||
CommandResultPermissionError(permission::PermissionType error, const std::string &extraMsg = "");
|
||||
};
|
||||
|
||||
CommandResult command_result::as_command_result() {
|
||||
if(this->is_detailed()) {
|
||||
const auto details = this->details();
|
||||
auto result = CommandResult{findError(details->error_id), details->extra_properties};
|
||||
this->release_details();
|
||||
return result;
|
||||
} else {
|
||||
const auto code = this->error_code();
|
||||
auto error = findError(this->error_code());
|
||||
if(code == error::server_insufficeient_permissions)
|
||||
return CommandResultPermissionError{(permission::PermissionType) this->permission_id()};
|
||||
else
|
||||
return CommandResult{error};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#define _NDEBUG
|
||||
|
||||
namespace ts {
|
||||
struct CommandResult;
|
||||
namespace permission {
|
||||
enum PermissionType : uint16_t;
|
||||
}
|
||||
|
||||
struct error {
|
||||
enum type : uint16_t {
|
||||
ok = 0x0,
|
||||
undefined = 0x1,
|
||||
not_implemented = 0x2,
|
||||
lib_time_limit_reached = 0x5,
|
||||
command_not_found = 0x100,
|
||||
unable_to_bind_network_port = 0x101,
|
||||
no_network_port_available = 0x102,
|
||||
client_invalid_id = 0x200,
|
||||
client_nickname_inuse = 0x201,
|
||||
invalid_error_code = 0x202,
|
||||
|
||||
client_protocol_limit_reached = 0x203,
|
||||
client_invalid_type = 0x204,
|
||||
client_already_subscribed = 0x205,
|
||||
client_not_logged_in = 0x206,
|
||||
client_could_not_validate_identity = 0x207,
|
||||
client_invalid_password = 0x208,
|
||||
client_too_many_clones_connected = 0x209,
|
||||
client_version_outdated = 0x20a,
|
||||
client_is_online = 0x20b,
|
||||
client_is_flooding = 0x20c,
|
||||
client_hacked = 0x20d,
|
||||
client_cannot_verify_now = 0x20e,
|
||||
client_login_not_permitted = 0x20f,
|
||||
client_not_subscribed = 0x210,
|
||||
client_unknown = 0x0211,
|
||||
client_join_rate_limit_reached = 0x0212,
|
||||
client_is_already_member_of_group = 0x0213,
|
||||
client_is_not_member_of_group = 0x0214,
|
||||
client_type_is_not_allowed = 0x0215,
|
||||
|
||||
channel_invalid_id = 0x300,
|
||||
channel_protocol_limit_reached = 0x301,
|
||||
channel_already_in = 0x302,
|
||||
channel_name_inuse = 0x303,
|
||||
channel_not_empty = 0x304,
|
||||
channel_can_not_delete_default = 0x305,
|
||||
channel_default_require_permanent = 0x306,
|
||||
channel_invalid_flags = 0x307,
|
||||
channel_parent_not_permanent = 0x308,
|
||||
channel_maxclients_reached = 0x309,
|
||||
channel_maxfamily_reached = 0x30a,
|
||||
channel_invalid_order = 0x30b,
|
||||
channel_no_filetransfer_supported = 0x30c,
|
||||
channel_invalid_password = 0x30d,
|
||||
channel_is_private_channel = 0x30e,
|
||||
channel_invalid_security_hash = 0x30f,
|
||||
channel_is_deleted = 0x310,
|
||||
channel_name_invalid = 0x311,
|
||||
channel_limit_reached = 0x312,
|
||||
|
||||
server_invalid_id = 0x400,
|
||||
server_running = 0x401,
|
||||
server_is_shutting_down = 0x402,
|
||||
server_maxclients_reached = 0x403,
|
||||
server_invalid_password = 0x404,
|
||||
server_deployment_active = 0x405,
|
||||
server_unable_to_stop_own_server = 0x406,
|
||||
server_is_virtual = 0x407,
|
||||
server_wrong_machineid = 0x408,
|
||||
server_is_not_running = 0x409,
|
||||
server_is_booting = 0x40a,
|
||||
server_status_invalid = 0x40b,
|
||||
server_modal_quit = 0x40c,
|
||||
server_version_outdated = 0x40d,
|
||||
server_already_joined = 0x40d,
|
||||
server_is_not_shutting_down = 0x40e,
|
||||
server_max_vs_reached = 0x40f,
|
||||
server_unbound = 0x410,
|
||||
server_join_rate_limit_reached = 0x411,
|
||||
|
||||
sql = 0x500,
|
||||
database_empty_result = 0x501,
|
||||
database_duplicate_entry = 0x502,
|
||||
database_no_modifications = 0x503,
|
||||
database_constraint = 0x504,
|
||||
database_reinvoke = 0x505,
|
||||
parameter_quote = 0x600,
|
||||
parameter_invalid_count = 0x601,
|
||||
parameter_invalid = 0x602,
|
||||
parameter_not_found = 0x603,
|
||||
parameter_convert = 0x604,
|
||||
parameter_invalid_size = 0x605,
|
||||
parameter_missing = 0x606,
|
||||
parameter_checksum = 0x607,
|
||||
vs_critical = 0x700,
|
||||
connection_lost = 0x701,
|
||||
not_connected = 0x702,
|
||||
no_cached_connection_info = 0x703,
|
||||
currently_not_possible = 0x704,
|
||||
failed_connection_initialisation = 0x705,
|
||||
could_not_resolve_hostname = 0x706,
|
||||
invalid_server_connection_handler_id = 0x707,
|
||||
could_not_initialise_input_client = 0x708,
|
||||
clientlibrary_not_initialised = 0x709,
|
||||
serverlibrary_not_initialised = 0x70a,
|
||||
whisper_too_many_targets = 0x70b,
|
||||
whisper_no_targets = 0x70c,
|
||||
file_invalid_name = 0x800,
|
||||
file_invalid_permissions = 0x801,
|
||||
file_already_exists = 0x802,
|
||||
file_not_found = 0x803,
|
||||
file_io_error = 0x804,
|
||||
file_invalid_transfer_id = 0x805,
|
||||
file_invalid_path = 0x806,
|
||||
file_no_files_available = 0x807,
|
||||
file_overwrite_excludes_resume = 0x808,
|
||||
file_invalid_size = 0x809,
|
||||
file_already_in_use = 0x80a,
|
||||
file_could_not_open_connection = 0x80b,
|
||||
file_no_space_left_on_device = 0x80c,
|
||||
file_exceeds_file_system_maximum_size = 0x80d,
|
||||
file_transfer_connection_timeout = 0x80e,
|
||||
file_connection_lost = 0x80f,
|
||||
file_exceeds_supplied_size = 0x810,
|
||||
file_transfer_complete = 0x811,
|
||||
file_transfer_canceled = 0x812,
|
||||
file_transfer_interrupted = 0x813,
|
||||
file_transfer_server_quota_exceeded = 0x814,
|
||||
file_transfer_client_quota_exceeded = 0x815,
|
||||
file_transfer_reset = 0x816,
|
||||
file_transfer_limit_reached = 0x817,
|
||||
server_insufficeient_permissions = 0xa08,
|
||||
accounting_slot_limit_reached = 0xb01,
|
||||
server_connect_banned = 0xd01,
|
||||
ban_flooding = 0xd03,
|
||||
token_invalid_id = 0xf00,
|
||||
web_handshake_invalid = 0x1001,
|
||||
web_handshake_unsupported = 0x1001,
|
||||
web_handshake_identity_unsupported = 0x1002,
|
||||
web_handshake_identity_proof_failed = 0x1003,
|
||||
web_handshake_identity_outdated = 0x1004,
|
||||
|
||||
music_invalid_id = 0x1100,
|
||||
music_limit_reached = 0x1101,
|
||||
music_client_limit_reached = 0x1102,
|
||||
music_invalid_player_state = 0x1103,
|
||||
music_invalid_action = 0x1104,
|
||||
music_no_player = 0x1105,
|
||||
music_disabled = 0x1105,
|
||||
playlist_invalid_id = 0x2100,
|
||||
playlist_invalid_song_id = 0x2101,
|
||||
playlist_already_in_use = 0x2102,
|
||||
playlist_is_in_use = 0x2103,
|
||||
query_not_exists = 0x1200,
|
||||
query_already_exists = 0x1201,
|
||||
|
||||
group_invalid_id = 0x1300,
|
||||
group_name_inuse = 0x1301,
|
||||
group_not_assigned_over_this_server = 0x1302,
|
||||
|
||||
conversation_invalid_id = 0x2200,
|
||||
conversation_more_data = 0x2201,
|
||||
conversation_is_private = 0x2202,
|
||||
|
||||
custom_error = 0xffff
|
||||
};
|
||||
};
|
||||
|
||||
struct detailed_command_result {
|
||||
error::type error_id;
|
||||
std::map<std::string, std::string> extra_properties;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no destructor!)
|
||||
* return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no destructor!)
|
||||
* return command_result{error::vs_critical, "unknown error"}; => To a lot of code
|
||||
*/
|
||||
struct command_result { /* fixed size of 8 (64 bits) */
|
||||
static constexpr uint64_t MASK_ERROR = ~((uint64_t) 1 << (sizeof(error::type) * 8));
|
||||
static constexpr uint64_t MASK_PERMISSION = ~((uint64_t) 1 << (sizeof(permission::PermissionType) * 8));
|
||||
|
||||
static constexpr uint8_t OFFSET_ERROR = (8 - sizeof(error::type)) * 8;
|
||||
static constexpr uint8_t OFFSET_PERMISSION = (8 - sizeof(permission::PermissionType) - sizeof(error::type)) * 8;
|
||||
/*
|
||||
* First bit is a flag bit which switches between detailed and code mode.
|
||||
* 0 means detailed (Because then we could interpret data as a ptr (all ptr are 8 bit aligned => 3 zero bits))
|
||||
* bits [0;64] => data ptr (needs to be zero at destruction to avoid memory leaks)
|
||||
*
|
||||
* 1 means code
|
||||
* bits [64 - sizeof(error::type);64] => error type | Usually evaluates to [48;64]
|
||||
* bits [64 - sizeof(error::type) - sizeof(permission::PermissionType);64 - sizeof(error::type)] => permission id | Usually evaluates to [32;48]
|
||||
*/
|
||||
uint64_t data = 0;
|
||||
|
||||
/* Test for mode 1 as described before */
|
||||
static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62);
|
||||
|
||||
[[nodiscard]] inline error::type error_code() const {
|
||||
if(this->is_detailed()) return this->details()->error_id;
|
||||
|
||||
return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool is_permission_error() const {
|
||||
return this->error_code() == error::server_insufficeient_permissions;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline permission::PermissionType permission_id() const {
|
||||
if(this->is_detailed()) return (permission::PermissionType) -1; /* not supported */
|
||||
|
||||
return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const detailed_command_result* details() const { return (detailed_command_result*) this->data; }
|
||||
[[nodiscard]] inline detailed_command_result* details() { return (detailed_command_result*) this->data; }
|
||||
|
||||
[[nodiscard]] inline bool is_detailed() const {
|
||||
return (this->data & 0x1UL) == 0;
|
||||
}
|
||||
|
||||
inline std::unique_ptr<detailed_command_result> release_details() {
|
||||
if(!this->is_detailed()) return nullptr;
|
||||
|
||||
auto result = this->details();
|
||||
this->data = 0;
|
||||
return std::unique_ptr<detailed_command_result>{result};
|
||||
}
|
||||
|
||||
/* Attention: Releases the internal detailed pointer! */
|
||||
inline CommandResult as_command_result();
|
||||
|
||||
#ifndef _NDEBUG /* We dont need to secure that because gcc deduct us to an uint64_t and the only advantage is the mem leak test which is deactivated anyways */
|
||||
command_result(command_result&) = delete;
|
||||
command_result(const command_result&) = delete;
|
||||
command_result(command_result&& other) : data(other.data) {
|
||||
other.data = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
command_result() = default;
|
||||
|
||||
explicit command_result(permission::PermissionType permission) {
|
||||
this->data = 0x01; /* the the type to 1 */
|
||||
|
||||
this->data |= (uint64_t) error::server_insufficeient_permissions << OFFSET_ERROR;
|
||||
this->data |= (uint64_t) permission << OFFSET_PERMISSION;
|
||||
}
|
||||
|
||||
|
||||
explicit command_result(error::type error) {
|
||||
this->data = 0x01; /* the the type to 1 */
|
||||
|
||||
this->data |= (uint64_t) error << (8 - sizeof(error::type)) * 8;
|
||||
}
|
||||
|
||||
command_result(error::type error, const std::string& message) {
|
||||
auto details_ptr = new detailed_command_result{};
|
||||
assert(((uintptr_t) details_ptr & 0x03U) == 0); // must be aligned!
|
||||
|
||||
this->data = (uintptr_t) details_ptr;
|
||||
|
||||
details_ptr->error_id = error;
|
||||
details_ptr->extra_properties["extra_msg"] = message;
|
||||
}
|
||||
|
||||
command_result(error::type error, const std::map<std::string, std::string>& properties) : command_result{error, std::string{""}} {
|
||||
assert(this->is_detailed());
|
||||
this->details()->extra_properties = properties;
|
||||
}
|
||||
|
||||
#ifndef _NDEBUG
|
||||
/* if we're not using any debug we dont have to use a deconstructor. A deconstructor prevent a direct uint64_t return as described above */
|
||||
~command_result() {
|
||||
if((this->data & 0x01) == 0x00) {
|
||||
// this->details needs to be removed 'till this gets destructed
|
||||
assert(this->data == 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
static_assert(sizeof(command_result) == 8);
|
||||
|
||||
struct ErrorType {
|
||||
public:
|
||||
static ErrorType Success;
|
||||
static ErrorType Costume;
|
||||
static ErrorType VSError;
|
||||
static ErrorType DBEmpty;
|
||||
|
||||
ErrorType(const uint16_t errorId, std::string name, std::string message) : errorId(errorId), name(std::move(name)), message(std::move(message)) {}
|
||||
ErrorType(const ErrorType& ref) = default;
|
||||
ErrorType(ErrorType&& ref) : errorId(ref.errorId), name(std::move(ref.name)), message(std::move(ref.message)) {}
|
||||
|
||||
uint16_t errorId;
|
||||
std::string name;
|
||||
std::string message;
|
||||
|
||||
bool operator==(const ErrorType& ref) const {
|
||||
return errorId == ref.errorId;
|
||||
}
|
||||
|
||||
bool operator!=(const ErrorType& ref) const { return !operator==(ref); }
|
||||
|
||||
ErrorType& operator=(const ErrorType& ref) {
|
||||
errorId = ref.errorId;
|
||||
name = ref.name;
|
||||
message = ref.message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if fail
|
||||
*/
|
||||
bool operator!() const {
|
||||
return errorId != 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern const std::vector<ErrorType> avariableErrors;
|
||||
extern ErrorType findError(uint16_t errorId);
|
||||
extern ErrorType findError(std::string key);
|
||||
|
||||
enum CommandResultType {
|
||||
GENERAL,
|
||||
PERM_ERROR
|
||||
};
|
||||
|
||||
struct CommandResult {
|
||||
public:
|
||||
static CommandResult Success;
|
||||
static CommandResult NotImplemented;
|
||||
|
||||
CommandResult(const CommandResult& ref) : _type(ref._type), error(ref.error), extraProperties(ref.extraProperties) {}
|
||||
CommandResult(CommandResult&& ref) : _type(ref._type), error(ref.error), extraProperties(ref.extraProperties) {}
|
||||
CommandResult(ErrorType error, const std::string &extraMsg = "") : error(std::move(error)) { if(extraMsg.empty()) return; /*extraProperties["extramsg"] = extraMsg; */extraProperties["extra_msg"] = extraMsg; }
|
||||
CommandResult(std::string error, const std::string &extraMsg = "") : error(findError(std::move(error))) { if(extraMsg.empty()) return; /*extraProperties["extramsg"] = extraMsg; */extraProperties["extra_msg"] = extraMsg; }
|
||||
CommandResult() : CommandResult(ErrorType::Success, ""){}
|
||||
CommandResult(ErrorType error, std::map<std::string, std::string> details) : error(error), extraProperties(std::move(details)) {}
|
||||
|
||||
bool operator==(const CommandResult& ref){
|
||||
return this->error == ref.error && ref.extraProperties == this->extraProperties;
|
||||
}
|
||||
|
||||
CommandResult& operator=(const CommandResult& ref)= default;
|
||||
|
||||
/**
|
||||
* @return true if fail
|
||||
*/
|
||||
bool operator!() const {
|
||||
return this->error != ErrorType::Success;
|
||||
}
|
||||
virtual CommandResultType type(){ return _type; }
|
||||
|
||||
ErrorType error;
|
||||
std::map<std::string, std::string> extraProperties;
|
||||
CommandResultType _type = CommandResultType::GENERAL;
|
||||
};
|
||||
|
||||
struct CommandResultPermissionError : public CommandResult {
|
||||
public:
|
||||
CommandResultPermissionError(permission::PermissionType error, const std::string &extraMsg = "");
|
||||
};
|
||||
|
||||
CommandResult command_result::as_command_result() {
|
||||
if(this->is_detailed()) {
|
||||
const auto details = this->details();
|
||||
auto result = CommandResult{findError(details->error_id), details->extra_properties};
|
||||
this->release_details();
|
||||
return result;
|
||||
} else {
|
||||
const auto code = this->error_code();
|
||||
auto error = findError(this->error_code());
|
||||
if(code == error::server_insufficeient_permissions)
|
||||
return CommandResultPermissionError{(permission::PermissionType) this->permission_id()};
|
||||
else
|
||||
return CommandResult{error};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef _NDEBUG
|
178
src/EventLoop.h
178
src/EventLoop.h
@ -1,90 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace ts {
|
||||
namespace event {
|
||||
class EventExecutor;
|
||||
|
||||
class EventEntry {
|
||||
friend class EventExecutor;
|
||||
public:
|
||||
virtual void event_execute(const std::chrono::system_clock::time_point& /* scheduled timestamp */) = 0;
|
||||
|
||||
private:
|
||||
void* _event_ptr = nullptr;
|
||||
};
|
||||
|
||||
template <typename class_t>
|
||||
class ProxiedEventEntry : public event::EventEntry {
|
||||
public:
|
||||
using callback_t = void(class_t::*)(const std::chrono::system_clock::time_point &);
|
||||
using static_callback_t = void(*)(class_t *, const std::chrono::system_clock::time_point &);
|
||||
|
||||
ProxiedEventEntry(const std::shared_ptr<class_t>& _instance, callback_t callback) : instance(_instance), callback(callback) { }
|
||||
|
||||
std::weak_ptr<class_t> instance;
|
||||
callback_t callback;
|
||||
|
||||
void event_execute(const std::chrono::system_clock::time_point &point) override {
|
||||
auto _instance = this->instance.lock();
|
||||
if(!_instance)
|
||||
return;
|
||||
|
||||
auto callback_ptr = (void**) &this->callback;
|
||||
(*(static_callback_t*) callback_ptr)(&*_instance, point);
|
||||
}
|
||||
};
|
||||
|
||||
class EventExecutor {
|
||||
public:
|
||||
explicit EventExecutor(const std::string& /* thread prefix */);
|
||||
virtual ~EventExecutor();
|
||||
|
||||
bool initialize(int /* num threads */);
|
||||
bool schedule(const std::shared_ptr<EventEntry>& /* entry */);
|
||||
bool cancel(const std::shared_ptr<EventEntry>& /* entry */); /* Note: Will not cancel already running executes */
|
||||
void shutdown();
|
||||
|
||||
inline const std::string& thread_prefix() const { return this->_thread_prefix; }
|
||||
|
||||
void threads(int /* num threads */);
|
||||
inline int threads() const { return this->target_threads; }
|
||||
private:
|
||||
struct LinkedEntry {
|
||||
LinkedEntry* previous;
|
||||
LinkedEntry* next;
|
||||
|
||||
std::chrono::system_clock::time_point scheduled;
|
||||
std::weak_ptr<EventEntry> entry;
|
||||
};
|
||||
|
||||
static void _executor(EventExecutor*);
|
||||
void _spawn_executor(std::unique_lock<std::mutex>&);
|
||||
void _shutdown(std::unique_lock<std::mutex>&);
|
||||
void _reset_events(std::unique_lock<std::mutex>&);
|
||||
|
||||
#ifndef WIN32
|
||||
void _reassign_thread_names(std::unique_lock<std::mutex>&);
|
||||
#endif
|
||||
|
||||
bool should_shutdown = true;
|
||||
bool should_adjust = false; /* thread adjustments */
|
||||
int target_threads = 0;
|
||||
|
||||
std::vector<std::thread> _threads;
|
||||
std::mutex lock;
|
||||
std::condition_variable condition;
|
||||
|
||||
LinkedEntry* head = nullptr;
|
||||
LinkedEntry* tail = nullptr;
|
||||
|
||||
std::string _thread_prefix;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace ts {
|
||||
namespace event {
|
||||
class EventExecutor;
|
||||
|
||||
class EventEntry {
|
||||
friend class EventExecutor;
|
||||
public:
|
||||
virtual void event_execute(const std::chrono::system_clock::time_point& /* scheduled timestamp */) = 0;
|
||||
|
||||
private:
|
||||
void* _event_ptr = nullptr;
|
||||
};
|
||||
|
||||
template <typename class_t>
|
||||
class ProxiedEventEntry : public event::EventEntry {
|
||||
public:
|
||||
using callback_t = void(class_t::*)(const std::chrono::system_clock::time_point &);
|
||||
using static_callback_t = void(*)(class_t *, const std::chrono::system_clock::time_point &);
|
||||
|
||||
ProxiedEventEntry(const std::shared_ptr<class_t>& _instance, callback_t callback) : instance(_instance), callback(callback) { }
|
||||
|
||||
std::weak_ptr<class_t> instance;
|
||||
callback_t callback;
|
||||
|
||||
void event_execute(const std::chrono::system_clock::time_point &point) override {
|
||||
auto _instance = this->instance.lock();
|
||||
if(!_instance)
|
||||
return;
|
||||
|
||||
auto callback_ptr = (void**) &this->callback;
|
||||
(*(static_callback_t*) callback_ptr)(&*_instance, point);
|
||||
}
|
||||
};
|
||||
|
||||
class EventExecutor {
|
||||
public:
|
||||
explicit EventExecutor(const std::string& /* thread prefix */);
|
||||
virtual ~EventExecutor();
|
||||
|
||||
bool initialize(int /* num threads */);
|
||||
bool schedule(const std::shared_ptr<EventEntry>& /* entry */);
|
||||
bool cancel(const std::shared_ptr<EventEntry>& /* entry */); /* Note: Will not cancel already running executes */
|
||||
void shutdown();
|
||||
|
||||
inline const std::string& thread_prefix() const { return this->_thread_prefix; }
|
||||
|
||||
void threads(int /* num threads */);
|
||||
inline int threads() const { return this->target_threads; }
|
||||
private:
|
||||
struct LinkedEntry {
|
||||
LinkedEntry* previous;
|
||||
LinkedEntry* next;
|
||||
|
||||
std::chrono::system_clock::time_point scheduled;
|
||||
std::weak_ptr<EventEntry> entry;
|
||||
};
|
||||
|
||||
static void _executor(EventExecutor*);
|
||||
void _spawn_executor(std::unique_lock<std::mutex>&);
|
||||
void _shutdown(std::unique_lock<std::mutex>&);
|
||||
void _reset_events(std::unique_lock<std::mutex>&);
|
||||
|
||||
#ifndef WIN32
|
||||
void _reassign_thread_names(std::unique_lock<std::mutex>&);
|
||||
#endif
|
||||
|
||||
bool should_shutdown = true;
|
||||
bool should_adjust = false; /* thread adjustments */
|
||||
int target_threads = 0;
|
||||
|
||||
std::vector<std::thread> _threads;
|
||||
std::mutex lock;
|
||||
std::condition_variable condition;
|
||||
|
||||
LinkedEntry* head = nullptr;
|
||||
LinkedEntry* tail = nullptr;
|
||||
|
||||
std::string _thread_prefix;
|
||||
};
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,242 +1,242 @@
|
||||
//
|
||||
// Created by wolverindev on 07.10.17.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
#include "Packet.h"
|
||||
#include "buffers.h"
|
||||
#include "misc/endianness.h"
|
||||
|
||||
using namespace std;
|
||||
namespace ts {
|
||||
namespace protocol {
|
||||
|
||||
PacketTypeInfo::PacketTypeInfo(const std::string& name, PacketType type, bool ack, int max_length) noexcept {
|
||||
this->data = new PacketTypeProperties{name, type, max_length, ack};
|
||||
this->owns_data = true;
|
||||
|
||||
if(type < 0x0F)
|
||||
types.insert({type, *this});
|
||||
}
|
||||
|
||||
PacketTypeInfo::~PacketTypeInfo() {
|
||||
if(this->owns_data)
|
||||
delete this->data;
|
||||
}
|
||||
|
||||
PacketTypeInfo::PacketTypeInfo(const PacketTypeInfo &red) : data(red.data) { }
|
||||
|
||||
std::map<int, PacketTypeInfo> PacketTypeInfo::types;
|
||||
PacketTypeInfo PacketTypeInfo::fromid(int id) {
|
||||
for(const auto& elm : types)
|
||||
if(elm.first == id) return elm.second;
|
||||
return PacketTypeInfo::Undefined;
|
||||
}
|
||||
|
||||
PacketTypeInfo PacketTypeInfo::Voice = {"Voice", PacketType::VOICE, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::VoiceWhisper = {"VoiceWhisper", PacketType::VOICE_WHISPER, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Command = {"Command", PacketType::COMMAND, true, 487};
|
||||
PacketTypeInfo PacketTypeInfo::CommandLow = {"CommandLow", PacketType::COMMAND_LOW, true, 487};
|
||||
PacketTypeInfo PacketTypeInfo::Ping = {"Ping", PacketType::PING, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Pong = {"Pong", PacketType::PONG, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Ack = {"Ack", PacketType::ACK, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::AckLow = {"AckLow", PacketType::ACK_LOW, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Init1 = {"Init1", PacketType::INIT1, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Undefined = {"Undefined", PacketType::UNDEFINED, false, 1024};
|
||||
|
||||
namespace PacketFlag {
|
||||
std::string to_string(PacketFlag flag){
|
||||
switch(flag){
|
||||
case Fragmented:
|
||||
return "Fragmented";
|
||||
case NewProtocol:
|
||||
return "NewProtocol";
|
||||
case Compressed:
|
||||
return "Compressed";
|
||||
case Unencrypted:
|
||||
return "Unencrypted";
|
||||
default:
|
||||
return "None";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicPacket::BasicPacket(size_t header_length, size_t data_length) {
|
||||
this->_header_length = (uint8_t) header_length;
|
||||
this->_buffer = pipes::buffer(MAC_SIZE + this->_header_length + data_length);
|
||||
memset(this->_buffer.data_ptr(), 0, this->_buffer.length());
|
||||
}
|
||||
|
||||
BasicPacket::~BasicPacket() {}
|
||||
|
||||
void BasicPacket::append_data(const std::vector<pipes::buffer> &data) {
|
||||
size_t length = 0;
|
||||
for(const auto& buffer : data)
|
||||
length += buffer.length();
|
||||
|
||||
/* we've to allocate a new buffer because out buffer is fixed in size */
|
||||
size_t index = this->_buffer.length();
|
||||
auto new_buffer = buffer::allocate_buffer(length + index);
|
||||
new_buffer.write(this->_buffer, index);
|
||||
|
||||
for(const auto& buffer : data) {
|
||||
new_buffer.write(buffer, buffer.length(), index);
|
||||
index += buffer.length();
|
||||
}
|
||||
|
||||
this->_buffer = new_buffer;
|
||||
}
|
||||
|
||||
std::string BasicPacket::flags() const {
|
||||
std::string result;
|
||||
|
||||
if(this->has_flag(PacketFlag::Unencrypted)) result += string(result.empty() ? "" : " | ") + "Unencrypted";
|
||||
if(this->has_flag(PacketFlag::Compressed)) result += string(result.empty() ? "" : " | ") + "Compressed";
|
||||
if(this->has_flag(PacketFlag::Fragmented)) result += string(result.empty() ? "" : " | ") + "Fragmented";
|
||||
if(this->has_flag(PacketFlag::NewProtocol)) result += string(result.empty() ? "" : " | ") + "NewProtocol";
|
||||
|
||||
if(result.empty()) result = "none";
|
||||
return result;
|
||||
}
|
||||
|
||||
void BasicPacket::applyPacketId(PacketIdManager& manager) {
|
||||
this->applyPacketId(manager.nextPacketId(this->type()), manager.generationId(this->type()));
|
||||
}
|
||||
void BasicPacket::applyPacketId(uint16_t packetId, uint16_t generationId) {
|
||||
if(this->memory_state.id_branded)
|
||||
throw std::logic_error("Packet already got a packet id!");
|
||||
this->memory_state.id_branded = true;
|
||||
this->setPacketId(packetId, generationId);
|
||||
}
|
||||
Command BasicPacket::asCommand() {
|
||||
return Command::parse(this->data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buffer -> [mac][Header [uint16 BE packetId | [uint8](4bit flags | 4bit type)]][Data]
|
||||
* @return
|
||||
*/
|
||||
std::unique_ptr<ServerPacket> ServerPacket::from_buffer(const pipes::buffer_view &buffer) {
|
||||
auto result = make_unique<ServerPacket>();
|
||||
|
||||
result->_buffer = buffer.own_buffer();
|
||||
result->_header_length = SERVER_HEADER_SIZE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ServerPacket::ServerPacket(uint8_t flagMask, const pipes::buffer_view& data) : BasicPacket(SERVER_HEADER_SIZE, data.length()) {
|
||||
this->header()[2] = flagMask;
|
||||
memcpy(this->data().data_ptr(), data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
ServerPacket::ServerPacket(const PacketTypeInfo& type, const pipes::buffer_view& data) : BasicPacket(SERVER_HEADER_SIZE, data.length()) {
|
||||
this->header()[2] |= (uint8_t) type.type();
|
||||
memcpy(this->data().data_ptr(), data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
ServerPacket::ServerPacket(ts::protocol::PacketTypeInfo type, size_t data_length) : BasicPacket(SERVER_HEADER_SIZE, data_length) {
|
||||
this->header()[2] |= type.type();
|
||||
}
|
||||
|
||||
ServerPacket::~ServerPacket() {}
|
||||
|
||||
uint16_t ServerPacket::packetId() const {
|
||||
return be2le16(&this->header()[0]);
|
||||
}
|
||||
|
||||
void ServerPacket::setPacketId(uint16_t pkId, uint16_t gen) {
|
||||
le2be16(pkId, &this->header()[0]);
|
||||
this->genId = gen;
|
||||
}
|
||||
|
||||
uint16_t ServerPacket::generationId() const {
|
||||
return this->genId;
|
||||
}
|
||||
|
||||
PacketTypeInfo ServerPacket::type() const {
|
||||
return PacketTypeInfo::fromid(this->header()[2] & 0xF);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ClientPacket> ClientPacket::from_buffer(const pipes::buffer_view &buffer) {
|
||||
auto result = make_unique<ClientPacket>();
|
||||
|
||||
result->_buffer = buffer.own_buffer();
|
||||
result->_header_length = CLIENT_HEADER_SIZE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ClientPacket::ClientPacket(const PacketTypeInfo &type, const pipes::buffer_view& data) : BasicPacket(CLIENT_HEADER_SIZE, data.length()) {
|
||||
this->header()[4] = type.type() & 0xF;
|
||||
memcpy(this->data().data_ptr(), data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
|
||||
ClientPacket::ClientPacket(const PacketTypeInfo &type, uint8_t flag_mask, const pipes::buffer_view& data) : ClientPacket(type, data) {
|
||||
this->header()[4] |= flag_mask;
|
||||
}
|
||||
|
||||
ClientPacket::~ClientPacket() {}
|
||||
|
||||
uint16_t ClientPacket::packetId() const {
|
||||
return be2le16(&this->header()[0]);
|
||||
}
|
||||
|
||||
uint16_t ClientPacket::generationId() const {
|
||||
return this->genId;
|
||||
}
|
||||
|
||||
PacketTypeInfo ClientPacket::type() const {
|
||||
return PacketTypeInfo::fromid(this->header()[4] & 0xF);
|
||||
}
|
||||
|
||||
void ClientPacket::type(const ts::protocol::PacketTypeInfo &type) {
|
||||
auto& field = this->header().data_ptr<uint8_t>()[4];
|
||||
field &= (uint8_t) ~0xF;
|
||||
field |= type.type();
|
||||
}
|
||||
|
||||
void ClientPacket::setPacketId(uint16_t pkId, uint16_t gen) {
|
||||
this->header()[0] = (uint8_t) ((pkId >> 8) & 0xFF);
|
||||
this->header()[1] = (uint8_t) ((pkId >> 0) & 0xFF);
|
||||
this->genId = gen;
|
||||
}
|
||||
|
||||
uint16_t ClientPacket::clientId() const {
|
||||
return be2le16(&this->header()[2]);
|
||||
}
|
||||
|
||||
void ClientPacket::clientId(uint16_t clId) {
|
||||
this->header()[2] = clId >> 8;
|
||||
this->header()[3] = clId & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ClientPacketParser::packet_id() const { return be2le16(this->_buffer.data_ptr<uint8_t>(), ClientPacketParser::kHeaderOffset + 0); }
|
||||
uint16_t ClientPacketParser::client_id() const { return be2le16(this->_buffer.data_ptr<uint8_t>(), ClientPacketParser::kHeaderOffset + 2); }
|
||||
uint8_t ClientPacketParser::type() const { return (uint8_t) this->_buffer[ClientPacketParser::kHeaderOffset + 4] & 0xFU; }
|
||||
uint8_t ClientPacketParser::flags() const { return (uint8_t) this->_buffer[ClientPacketParser::kHeaderOffset + 4] & 0xF0U; }
|
||||
|
||||
bool ClientPacketParser::is_encrypted() const {
|
||||
if(this->decrypted) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Unencrypted) == 0;
|
||||
}
|
||||
|
||||
bool ClientPacketParser::is_compressed() const {
|
||||
if(this->uncompressed) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Compressed) > 0;
|
||||
}
|
||||
|
||||
bool ClientPacketParser::is_fragmented() const {
|
||||
if(this->defragmented) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Fragmented) > 0;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Created by wolverindev on 07.10.17.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
#include "Packet.h"
|
||||
#include "buffers.h"
|
||||
#include "misc/endianness.h"
|
||||
|
||||
using namespace std;
|
||||
namespace ts {
|
||||
namespace protocol {
|
||||
|
||||
PacketTypeInfo::PacketTypeInfo(const std::string& name, PacketType type, bool ack, int max_length) noexcept {
|
||||
this->data = new PacketTypeProperties{name, type, max_length, ack};
|
||||
this->owns_data = true;
|
||||
|
||||
if(type < 0x0F)
|
||||
types.insert({type, *this});
|
||||
}
|
||||
|
||||
PacketTypeInfo::~PacketTypeInfo() {
|
||||
if(this->owns_data)
|
||||
delete this->data;
|
||||
}
|
||||
|
||||
PacketTypeInfo::PacketTypeInfo(const PacketTypeInfo &red) : data(red.data) { }
|
||||
|
||||
std::map<int, PacketTypeInfo> PacketTypeInfo::types;
|
||||
PacketTypeInfo PacketTypeInfo::fromid(int id) {
|
||||
for(const auto& elm : types)
|
||||
if(elm.first == id) return elm.second;
|
||||
return PacketTypeInfo::Undefined;
|
||||
}
|
||||
|
||||
PacketTypeInfo PacketTypeInfo::Voice = {"Voice", PacketType::VOICE, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::VoiceWhisper = {"VoiceWhisper", PacketType::VOICE_WHISPER, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Command = {"Command", PacketType::COMMAND, true, 487};
|
||||
PacketTypeInfo PacketTypeInfo::CommandLow = {"CommandLow", PacketType::COMMAND_LOW, true, 487};
|
||||
PacketTypeInfo PacketTypeInfo::Ping = {"Ping", PacketType::PING, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Pong = {"Pong", PacketType::PONG, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Ack = {"Ack", PacketType::ACK, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::AckLow = {"AckLow", PacketType::ACK_LOW, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Init1 = {"Init1", PacketType::INIT1, false, 1024};
|
||||
PacketTypeInfo PacketTypeInfo::Undefined = {"Undefined", PacketType::UNDEFINED, false, 1024};
|
||||
|
||||
namespace PacketFlag {
|
||||
std::string to_string(PacketFlag flag){
|
||||
switch(flag){
|
||||
case Fragmented:
|
||||
return "Fragmented";
|
||||
case NewProtocol:
|
||||
return "NewProtocol";
|
||||
case Compressed:
|
||||
return "Compressed";
|
||||
case Unencrypted:
|
||||
return "Unencrypted";
|
||||
default:
|
||||
return "None";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicPacket::BasicPacket(size_t header_length, size_t data_length) {
|
||||
this->_header_length = (uint8_t) header_length;
|
||||
this->_buffer = pipes::buffer(MAC_SIZE + this->_header_length + data_length);
|
||||
memset(this->_buffer.data_ptr(), 0, this->_buffer.length());
|
||||
}
|
||||
|
||||
BasicPacket::~BasicPacket() {}
|
||||
|
||||
void BasicPacket::append_data(const std::vector<pipes::buffer> &data) {
|
||||
size_t length = 0;
|
||||
for(const auto& buffer : data)
|
||||
length += buffer.length();
|
||||
|
||||
/* we've to allocate a new buffer because out buffer is fixed in size */
|
||||
size_t index = this->_buffer.length();
|
||||
auto new_buffer = buffer::allocate_buffer(length + index);
|
||||
new_buffer.write(this->_buffer, index);
|
||||
|
||||
for(const auto& buffer : data) {
|
||||
new_buffer.write(buffer, buffer.length(), index);
|
||||
index += buffer.length();
|
||||
}
|
||||
|
||||
this->_buffer = new_buffer;
|
||||
}
|
||||
|
||||
std::string BasicPacket::flags() const {
|
||||
std::string result;
|
||||
|
||||
if(this->has_flag(PacketFlag::Unencrypted)) result += string(result.empty() ? "" : " | ") + "Unencrypted";
|
||||
if(this->has_flag(PacketFlag::Compressed)) result += string(result.empty() ? "" : " | ") + "Compressed";
|
||||
if(this->has_flag(PacketFlag::Fragmented)) result += string(result.empty() ? "" : " | ") + "Fragmented";
|
||||
if(this->has_flag(PacketFlag::NewProtocol)) result += string(result.empty() ? "" : " | ") + "NewProtocol";
|
||||
|
||||
if(result.empty()) result = "none";
|
||||
return result;
|
||||
}
|
||||
|
||||
void BasicPacket::applyPacketId(PacketIdManager& manager) {
|
||||
this->applyPacketId(manager.nextPacketId(this->type()), manager.generationId(this->type()));
|
||||
}
|
||||
void BasicPacket::applyPacketId(uint16_t packetId, uint16_t generationId) {
|
||||
if(this->memory_state.id_branded)
|
||||
throw std::logic_error("Packet already got a packet id!");
|
||||
this->memory_state.id_branded = true;
|
||||
this->setPacketId(packetId, generationId);
|
||||
}
|
||||
Command BasicPacket::asCommand() {
|
||||
return Command::parse(this->data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buffer -> [mac][Header [uint16 BE packetId | [uint8](4bit flags | 4bit type)]][Data]
|
||||
* @return
|
||||
*/
|
||||
std::unique_ptr<ServerPacket> ServerPacket::from_buffer(const pipes::buffer_view &buffer) {
|
||||
auto result = make_unique<ServerPacket>();
|
||||
|
||||
result->_buffer = buffer.own_buffer();
|
||||
result->_header_length = SERVER_HEADER_SIZE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ServerPacket::ServerPacket(uint8_t flagMask, const pipes::buffer_view& data) : BasicPacket(SERVER_HEADER_SIZE, data.length()) {
|
||||
this->header()[2] = flagMask;
|
||||
memcpy(this->data().data_ptr(), data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
ServerPacket::ServerPacket(const PacketTypeInfo& type, const pipes::buffer_view& data) : BasicPacket(SERVER_HEADER_SIZE, data.length()) {
|
||||
this->header()[2] |= (uint8_t) type.type();
|
||||
memcpy(this->data().data_ptr(), data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
ServerPacket::ServerPacket(ts::protocol::PacketTypeInfo type, size_t data_length) : BasicPacket(SERVER_HEADER_SIZE, data_length) {
|
||||
this->header()[2] |= type.type();
|
||||
}
|
||||
|
||||
ServerPacket::~ServerPacket() {}
|
||||
|
||||
uint16_t ServerPacket::packetId() const {
|
||||
return be2le16(&this->header()[0]);
|
||||
}
|
||||
|
||||
void ServerPacket::setPacketId(uint16_t pkId, uint16_t gen) {
|
||||
le2be16(pkId, &this->header()[0]);
|
||||
this->genId = gen;
|
||||
}
|
||||
|
||||
uint16_t ServerPacket::generationId() const {
|
||||
return this->genId;
|
||||
}
|
||||
|
||||
PacketTypeInfo ServerPacket::type() const {
|
||||
return PacketTypeInfo::fromid(this->header()[2] & 0xF);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ClientPacket> ClientPacket::from_buffer(const pipes::buffer_view &buffer) {
|
||||
auto result = make_unique<ClientPacket>();
|
||||
|
||||
result->_buffer = buffer.own_buffer();
|
||||
result->_header_length = CLIENT_HEADER_SIZE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ClientPacket::ClientPacket(const PacketTypeInfo &type, const pipes::buffer_view& data) : BasicPacket(CLIENT_HEADER_SIZE, data.length()) {
|
||||
this->header()[4] = type.type() & 0xF;
|
||||
memcpy(this->data().data_ptr(), data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
|
||||
ClientPacket::ClientPacket(const PacketTypeInfo &type, uint8_t flag_mask, const pipes::buffer_view& data) : ClientPacket(type, data) {
|
||||
this->header()[4] |= flag_mask;
|
||||
}
|
||||
|
||||
ClientPacket::~ClientPacket() {}
|
||||
|
||||
uint16_t ClientPacket::packetId() const {
|
||||
return be2le16(&this->header()[0]);
|
||||
}
|
||||
|
||||
uint16_t ClientPacket::generationId() const {
|
||||
return this->genId;
|
||||
}
|
||||
|
||||
PacketTypeInfo ClientPacket::type() const {
|
||||
return PacketTypeInfo::fromid(this->header()[4] & 0xF);
|
||||
}
|
||||
|
||||
void ClientPacket::type(const ts::protocol::PacketTypeInfo &type) {
|
||||
auto& field = this->header().data_ptr<uint8_t>()[4];
|
||||
field &= (uint8_t) ~0xF;
|
||||
field |= type.type();
|
||||
}
|
||||
|
||||
void ClientPacket::setPacketId(uint16_t pkId, uint16_t gen) {
|
||||
this->header()[0] = (uint8_t) ((pkId >> 8) & 0xFF);
|
||||
this->header()[1] = (uint8_t) ((pkId >> 0) & 0xFF);
|
||||
this->genId = gen;
|
||||
}
|
||||
|
||||
uint16_t ClientPacket::clientId() const {
|
||||
return be2le16(&this->header()[2]);
|
||||
}
|
||||
|
||||
void ClientPacket::clientId(uint16_t clId) {
|
||||
this->header()[2] = clId >> 8;
|
||||
this->header()[3] = clId & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ClientPacketParser::packet_id() const { return be2le16(this->_buffer.data_ptr<uint8_t>(), ClientPacketParser::kHeaderOffset + 0); }
|
||||
uint16_t ClientPacketParser::client_id() const { return be2le16(this->_buffer.data_ptr<uint8_t>(), ClientPacketParser::kHeaderOffset + 2); }
|
||||
uint8_t ClientPacketParser::type() const { return (uint8_t) this->_buffer[ClientPacketParser::kHeaderOffset + 4] & 0xFU; }
|
||||
uint8_t ClientPacketParser::flags() const { return (uint8_t) this->_buffer[ClientPacketParser::kHeaderOffset + 4] & 0xF0U; }
|
||||
|
||||
bool ClientPacketParser::is_encrypted() const {
|
||||
if(this->decrypted) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Unencrypted) == 0;
|
||||
}
|
||||
|
||||
bool ClientPacketParser::is_compressed() const {
|
||||
if(this->uncompressed) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Compressed) > 0;
|
||||
}
|
||||
|
||||
bool ClientPacketParser::is_fragmented() const {
|
||||
if(this->defragmented) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Fragmented) > 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,371 +1,371 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <ThreadPool/Future.h>
|
||||
#include <pipes/buffer.h>
|
||||
#include "../query/Command.h"
|
||||
|
||||
namespace ts {
|
||||
namespace protocol {
|
||||
enum PacketType : uint8_t {
|
||||
VOICE = 0x00,
|
||||
VOICE_WHISPER = 0x01,
|
||||
COMMAND = 0x02,
|
||||
COMMAND_LOW = 0x03,
|
||||
PING = 0x04,
|
||||
PONG = 0x05,
|
||||
ACK = 0x06,
|
||||
ACK_LOW = 0x07,
|
||||
INIT1 = 0x08,
|
||||
|
||||
PACKET_MAX = INIT1,
|
||||
UNDEFINED = 0xFF
|
||||
};
|
||||
|
||||
struct PacketTypeProperties {
|
||||
std::string name;
|
||||
PacketType type;
|
||||
int max_length;
|
||||
bool requireAcknowledge;
|
||||
};
|
||||
|
||||
class PacketTypeInfo {
|
||||
public:
|
||||
static PacketTypeInfo Voice;
|
||||
static PacketTypeInfo VoiceWhisper;
|
||||
static PacketTypeInfo Command;
|
||||
static PacketTypeInfo CommandLow;
|
||||
static PacketTypeInfo Ping;
|
||||
static PacketTypeInfo Pong;
|
||||
static PacketTypeInfo Ack;
|
||||
static PacketTypeInfo AckLow;
|
||||
static PacketTypeInfo Init1;
|
||||
static PacketTypeInfo Undefined;
|
||||
|
||||
static PacketTypeInfo fromid(int id);
|
||||
|
||||
std::string name() const { return data->name; }
|
||||
PacketType type() const { return data->type; }
|
||||
|
||||
bool requireAcknowledge(){ return data->requireAcknowledge; }
|
||||
|
||||
bool operator==(const PacketTypeInfo& other) const {
|
||||
return other.data->type == this->data->type;
|
||||
}
|
||||
|
||||
bool operator!=(const PacketTypeInfo& other){
|
||||
return other.data->type != this->data->type;
|
||||
}
|
||||
|
||||
int max_length() const { return data->max_length; }
|
||||
inline bool fragmentable() { return *this == PacketTypeInfo::Command || *this == PacketTypeInfo::CommandLow; }
|
||||
inline bool compressable() { return *this == PacketTypeInfo::Command || *this == PacketTypeInfo::CommandLow; }
|
||||
|
||||
PacketTypeInfo(const PacketTypeInfo&);
|
||||
PacketTypeInfo(PacketTypeInfo&& remote) : data(remote.data) {}
|
||||
|
||||
~PacketTypeInfo();
|
||||
private:
|
||||
static std::map<int, PacketTypeInfo> types;
|
||||
PacketTypeInfo(const std::string&, PacketType, bool, int) noexcept;
|
||||
PacketTypeProperties* data;
|
||||
bool owns_data = false;
|
||||
};
|
||||
|
||||
struct PacketIdManagerData {
|
||||
PacketIdManagerData(){
|
||||
memset(this->packetCounter, 0, sizeof(uint32_t) * 16);
|
||||
}
|
||||
uint32_t packetCounter[16]{};
|
||||
};
|
||||
|
||||
class PacketIdManager {
|
||||
public:
|
||||
PacketIdManager() : data(new PacketIdManagerData){}
|
||||
~PacketIdManager() = default;
|
||||
PacketIdManager(const PacketIdManager& ref) : data(ref.data) {}
|
||||
PacketIdManager(PacketIdManager&& ref) : data(std::move(ref.data)) {}
|
||||
|
||||
uint16_t nextPacketId(const PacketTypeInfo &type){
|
||||
return static_cast<uint16_t>(data->packetCounter[type.type()]++ & 0xFFFF);
|
||||
}
|
||||
|
||||
uint16_t currentPacketId(const PacketTypeInfo &type){
|
||||
return static_cast<uint16_t>(data->packetCounter[type.type()] & 0xFFFF);
|
||||
}
|
||||
|
||||
uint16_t generationId(const PacketTypeInfo &type){
|
||||
return static_cast<uint16_t>((data->packetCounter[type.type()] >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
memset(&data->packetCounter[0], 0, sizeof(uint32_t) * 16);
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<PacketIdManagerData> data;
|
||||
};
|
||||
|
||||
namespace PacketFlag {
|
||||
enum PacketFlag : uint8_t {
|
||||
None = 0x00,
|
||||
Fragmented = 0x10, //If packet type voice then its toggle the CELT Mono
|
||||
NewProtocol = 0x20,
|
||||
Compressed = 0x40, //If packet type voice than its the header
|
||||
Unencrypted = 0x80
|
||||
};
|
||||
typedef uint8_t PacketFlags;
|
||||
|
||||
std::string to_string(PacketFlag flag);
|
||||
}
|
||||
|
||||
#define MAC_SIZE 8
|
||||
#define SERVER_HEADER_SIZE 3
|
||||
#define CLIENT_HEADER_SIZE 5
|
||||
|
||||
class BasicPacket {
|
||||
public:
|
||||
explicit BasicPacket(size_t header_length, size_t data_length);
|
||||
virtual ~BasicPacket();
|
||||
|
||||
BasicPacket(const BasicPacket&) = delete;
|
||||
BasicPacket(BasicPacket&&) = delete;
|
||||
|
||||
virtual uint16_t packetId() const = 0;
|
||||
virtual uint16_t generationId() const = 0;
|
||||
virtual PacketTypeInfo type() const = 0;
|
||||
|
||||
/* packet flag info */
|
||||
inline bool has_flag(PacketFlag::PacketFlag flag) const { return this->_flags_type_byte() & flag; }
|
||||
inline uint8_t flag_mask() const { return this->_flags_type_byte(); };
|
||||
[[nodiscard]] std::string flags() const;
|
||||
|
||||
/* manipulate flags */
|
||||
inline void set_flags(PacketFlag::PacketFlags flags) {
|
||||
uint8_t& byte = this->_flags_type_byte();
|
||||
byte &= 0xF; /* clear all flags */
|
||||
byte |= (flags & 0xF0);
|
||||
}
|
||||
inline void enable_flag(PacketFlag::PacketFlag flag){ this->toggle_flag(flag, true); }
|
||||
inline void toggle_flag(PacketFlag::PacketFlag flag, bool state) {
|
||||
if(state)
|
||||
this->_flags_type_byte() |= flag;
|
||||
else
|
||||
this->_flags_type_byte() &= (uint8_t) ~flag;
|
||||
}
|
||||
|
||||
virtual void applyPacketId(PacketIdManager &);
|
||||
virtual void applyPacketId(uint16_t, uint16_t);
|
||||
|
||||
void setListener(std::unique_ptr<threads::Future<bool>> listener){
|
||||
if(!this->type().requireAcknowledge())
|
||||
throw std::logic_error("Packet type does not support a acknowledge listener!");
|
||||
this->listener = std::move(listener);
|
||||
}
|
||||
inline std::unique_ptr<threads::Future<bool>>& getListener() { return this->listener; }
|
||||
|
||||
inline size_t length() const { return this->_buffer.length(); }
|
||||
inline const pipes::buffer_view mac() const { return this->_buffer.view(0, MAC_SIZE); }
|
||||
inline pipes::buffer mac() { return this->_buffer.range(0, MAC_SIZE); }
|
||||
inline size_t mac_length() const { return MAC_SIZE; }
|
||||
|
||||
inline const pipes::buffer_view header() const { return this->_buffer.view(MAC_SIZE, this->_header_length); }
|
||||
inline pipes::buffer header() { return this->_buffer.range(MAC_SIZE, this->_header_length); }
|
||||
inline size_t header_length() const { return this->_header_length; }
|
||||
|
||||
inline size_t data_length() const { return this->_buffer.length() - (MAC_SIZE + this->_header_length); }
|
||||
inline const pipes::buffer_view data() const { return this->_buffer.view(MAC_SIZE + this->_header_length); }
|
||||
inline pipes::buffer data() { return this->_buffer.range(MAC_SIZE + this->_header_length); }
|
||||
|
||||
void append_data(const std::vector<pipes::buffer> &data);
|
||||
|
||||
inline void data(const pipes::buffer_view &data){
|
||||
this->_buffer.resize(MAC_SIZE + this->_header_length + data.length());
|
||||
memcpy((char*) this->_buffer.data_ptr() + MAC_SIZE + this->_header_length, data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
inline void mac(const pipes::buffer_view &_new){
|
||||
assert(_new.length() >= MAC_SIZE);
|
||||
memcpy(this->_buffer.data_ptr(), _new.data_ptr(), MAC_SIZE);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool isEncrypted() const { return this->memory_state.encrypted; }
|
||||
inline void setEncrypted(bool flag){ this->memory_state.encrypted = flag; }
|
||||
|
||||
[[nodiscard]] inline bool isCompressed() const { return this->memory_state.compressed; }
|
||||
inline void setCompressed(bool flag){ this->memory_state.compressed = flag; }
|
||||
|
||||
[[nodiscard]] inline bool isFragmentEntry() const { return this->memory_state.fragment_entry; }
|
||||
inline void setFragmentedEntry(bool flag){ this->memory_state.fragment_entry = flag; }
|
||||
|
||||
Command asCommand();
|
||||
|
||||
//Has the size of a byte
|
||||
union {
|
||||
#ifdef WIN32
|
||||
__pragma(pack(push, 1))
|
||||
#endif
|
||||
struct {
|
||||
bool encrypted: 1;
|
||||
bool compressed: 1;
|
||||
bool fragment_entry: 1;
|
||||
|
||||
bool id_branded: 1;
|
||||
}
|
||||
#ifdef WIN32
|
||||
__pragma(pack(pop));
|
||||
#else
|
||||
__attribute__((packed));
|
||||
#endif
|
||||
|
||||
uint8_t flags = 0;
|
||||
} memory_state;
|
||||
|
||||
pipes::buffer buffer() { return this->_buffer; }
|
||||
void buffer(pipes::buffer buffer) {
|
||||
assert(buffer.length() >= this->_header_length + MAC_SIZE);
|
||||
this->_buffer = std::move(buffer);
|
||||
}
|
||||
protected:
|
||||
BasicPacket() = default;
|
||||
|
||||
virtual const uint8_t& _flags_type_byte() const = 0;
|
||||
virtual uint8_t& _flags_type_byte() = 0;
|
||||
|
||||
virtual void setPacketId(uint16_t, uint16_t) = 0;
|
||||
uint8_t _header_length;
|
||||
pipes::buffer _buffer;
|
||||
|
||||
uint16_t genId = 0;
|
||||
std::unique_ptr<threads::Future<bool>> listener;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Packet from the client
|
||||
*/
|
||||
class ClientPacket : public BasicPacket {
|
||||
friend std::unique_ptr<ClientPacket> std::make_unique<ClientPacket>();
|
||||
public:
|
||||
static constexpr size_t META_MAC_SIZE = 8;
|
||||
static constexpr size_t META_HEADER_SIZE = CLIENT_HEADER_SIZE;
|
||||
static constexpr size_t META_SIZE = META_MAC_SIZE + META_HEADER_SIZE;
|
||||
|
||||
[[nodiscard]] static std::unique_ptr<ClientPacket> from_buffer(const pipes::buffer_view& buffer);
|
||||
|
||||
ClientPacket(const PacketTypeInfo& type, const pipes::buffer_view& data);
|
||||
ClientPacket(const PacketTypeInfo& type, uint8_t flag_mask, const pipes::buffer_view& data);
|
||||
~ClientPacket() override;
|
||||
ClientPacket(const ClientPacket&) = delete;
|
||||
ClientPacket(ClientPacket&&) = delete;
|
||||
|
||||
uint16_t clientId() const;
|
||||
void clientId(uint16_t);
|
||||
|
||||
uint16_t packetId() const override;
|
||||
|
||||
uint16_t generationId() const override;
|
||||
void generationId(uint16_t generation) { this->genId = generation; }
|
||||
|
||||
PacketTypeInfo type() const override;
|
||||
void type(const PacketTypeInfo&);
|
||||
|
||||
private:
|
||||
ClientPacket() = default;
|
||||
|
||||
const uint8_t &_flags_type_byte() const override {
|
||||
return this->header().data_ptr<uint8_t>()[4];
|
||||
}
|
||||
|
||||
uint8_t &_flags_type_byte() override {
|
||||
return this->header().data_ptr<uint8_t>()[4];
|
||||
}
|
||||
|
||||
void setPacketId(uint16_t, uint16_t) override;
|
||||
};
|
||||
|
||||
class ClientPacketParser {
|
||||
public:
|
||||
constexpr static auto kHeaderOffset = 8;
|
||||
constexpr static auto kHeaderLength = CLIENT_HEADER_SIZE;
|
||||
|
||||
constexpr static auto kPayloadOffset = kHeaderOffset + CLIENT_HEADER_SIZE;
|
||||
explicit ClientPacketParser(pipes::buffer_view buffer) : _buffer{std::move(buffer)} {}
|
||||
ClientPacketParser(const ClientPacketParser&) = delete;
|
||||
|
||||
[[nodiscard]] inline bool valid() const {
|
||||
if(this->_buffer.length() < kPayloadOffset) return false;
|
||||
return this->type() <= 8;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* data_ptr() const { return this->_buffer.data_ptr(); }
|
||||
[[nodiscard]] inline void* mutable_data_ptr() { return (void*) this->_buffer.data_ptr(); }
|
||||
|
||||
[[nodiscard]] inline pipes::buffer_view buffer() const { return this->_buffer; }
|
||||
[[nodiscard]] inline pipes::buffer_view mac() const { return this->_buffer.view(0, 8); }
|
||||
[[nodiscard]] inline pipes::buffer_view payload() const { return this->_buffer.view(kPayloadOffset); }
|
||||
[[nodiscard]] inline size_t payload_length() const { return this->_buffer.length() - kPayloadOffset; }
|
||||
|
||||
[[nodiscard]] uint16_t client_id() const;
|
||||
[[nodiscard]] uint16_t packet_id() const;
|
||||
[[nodiscard]] uint8_t type() const;
|
||||
[[nodiscard]] uint8_t flags() const;
|
||||
|
||||
[[nodiscard]] bool is_encrypted() const;
|
||||
[[nodiscard]] bool is_compressed() const;
|
||||
[[nodiscard]] bool is_fragmented() const;
|
||||
|
||||
[[nodiscard]] uint16_t estimated_generation() const { return this->generation; }
|
||||
void set_estimated_generation(uint16_t gen) { this->generation = gen; }
|
||||
|
||||
inline void set_decrypted() { this->decrypted = true; }
|
||||
inline void set_uncompressed() { this->uncompressed = true; }
|
||||
inline void set_defragmented() { this->defragmented = true; }
|
||||
private:
|
||||
uint16_t generation{};
|
||||
bool decrypted{false}, uncompressed{false}, defragmented{false};
|
||||
pipes::buffer_view _buffer{};
|
||||
};
|
||||
|
||||
/**
|
||||
* Packet from the server
|
||||
*/
|
||||
class ServerPacket : public BasicPacket {
|
||||
friend std::unique_ptr<ServerPacket> std::make_unique<ServerPacket>();
|
||||
public:
|
||||
static constexpr size_t META_MAC_SIZE = 8;
|
||||
static constexpr size_t META_HEADER_SIZE = SERVER_HEADER_SIZE;
|
||||
static constexpr size_t META_SIZE = META_MAC_SIZE + META_HEADER_SIZE;
|
||||
|
||||
[[nodiscard]] static std::unique_ptr<ServerPacket> from_buffer(const pipes::buffer_view& buffer);
|
||||
|
||||
ServerPacket(uint8_t flagMask, const pipes::buffer_view& data);
|
||||
ServerPacket(const PacketTypeInfo& type, const pipes::buffer_view& data);
|
||||
ServerPacket(PacketTypeInfo type, size_t /* data length */);
|
||||
~ServerPacket() override;
|
||||
|
||||
ServerPacket(const ServerPacket&) = delete;
|
||||
ServerPacket(ServerPacket&&) = delete;
|
||||
|
||||
[[nodiscard]] uint16_t packetId() const override;
|
||||
[[nodiscard]] uint16_t generationId() const override;
|
||||
void generationId(uint16_t generation) { this->genId = generation; }
|
||||
[[nodiscard]] PacketTypeInfo type() const override;
|
||||
|
||||
private:
|
||||
ServerPacket() = default;
|
||||
|
||||
[[nodiscard]] const uint8_t &_flags_type_byte() const override {
|
||||
return this->header().data_ptr<uint8_t>()[2];
|
||||
}
|
||||
|
||||
uint8_t &_flags_type_byte() override {
|
||||
return this->header().data_ptr<uint8_t>()[2];
|
||||
}
|
||||
|
||||
void setPacketId(uint16_t, uint16_t) override;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <ThreadPool/Future.h>
|
||||
#include <pipes/buffer.h>
|
||||
#include "../query/Command.h"
|
||||
|
||||
namespace ts {
|
||||
namespace protocol {
|
||||
enum PacketType : uint8_t {
|
||||
VOICE = 0x00,
|
||||
VOICE_WHISPER = 0x01,
|
||||
COMMAND = 0x02,
|
||||
COMMAND_LOW = 0x03,
|
||||
PING = 0x04,
|
||||
PONG = 0x05,
|
||||
ACK = 0x06,
|
||||
ACK_LOW = 0x07,
|
||||
INIT1 = 0x08,
|
||||
|
||||
PACKET_MAX = INIT1,
|
||||
UNDEFINED = 0xFF
|
||||
};
|
||||
|
||||
struct PacketTypeProperties {
|
||||
std::string name;
|
||||
PacketType type;
|
||||
int max_length;
|
||||
bool requireAcknowledge;
|
||||
};
|
||||
|
||||
class PacketTypeInfo {
|
||||
public:
|
||||
static PacketTypeInfo Voice;
|
||||
static PacketTypeInfo VoiceWhisper;
|
||||
static PacketTypeInfo Command;
|
||||
static PacketTypeInfo CommandLow;
|
||||
static PacketTypeInfo Ping;
|
||||
static PacketTypeInfo Pong;
|
||||
static PacketTypeInfo Ack;
|
||||
static PacketTypeInfo AckLow;
|
||||
static PacketTypeInfo Init1;
|
||||
static PacketTypeInfo Undefined;
|
||||
|
||||
static PacketTypeInfo fromid(int id);
|
||||
|
||||
std::string name() const { return data->name; }
|
||||
PacketType type() const { return data->type; }
|
||||
|
||||
bool requireAcknowledge(){ return data->requireAcknowledge; }
|
||||
|
||||
bool operator==(const PacketTypeInfo& other) const {
|
||||
return other.data->type == this->data->type;
|
||||
}
|
||||
|
||||
bool operator!=(const PacketTypeInfo& other){
|
||||
return other.data->type != this->data->type;
|
||||
}
|
||||
|
||||
int max_length() const { return data->max_length; }
|
||||
inline bool fragmentable() { return *this == PacketTypeInfo::Command || *this == PacketTypeInfo::CommandLow; }
|
||||
inline bool compressable() { return *this == PacketTypeInfo::Command || *this == PacketTypeInfo::CommandLow; }
|
||||
|
||||
PacketTypeInfo(const PacketTypeInfo&);
|
||||
PacketTypeInfo(PacketTypeInfo&& remote) : data(remote.data) {}
|
||||
|
||||
~PacketTypeInfo();
|
||||
private:
|
||||
static std::map<int, PacketTypeInfo> types;
|
||||
PacketTypeInfo(const std::string&, PacketType, bool, int) noexcept;
|
||||
PacketTypeProperties* data;
|
||||
bool owns_data = false;
|
||||
};
|
||||
|
||||
struct PacketIdManagerData {
|
||||
PacketIdManagerData(){
|
||||
memset(this->packetCounter, 0, sizeof(uint32_t) * 16);
|
||||
}
|
||||
uint32_t packetCounter[16]{};
|
||||
};
|
||||
|
||||
class PacketIdManager {
|
||||
public:
|
||||
PacketIdManager() : data(new PacketIdManagerData){}
|
||||
~PacketIdManager() = default;
|
||||
PacketIdManager(const PacketIdManager& ref) : data(ref.data) {}
|
||||
PacketIdManager(PacketIdManager&& ref) : data(std::move(ref.data)) {}
|
||||
|
||||
uint16_t nextPacketId(const PacketTypeInfo &type){
|
||||
return static_cast<uint16_t>(data->packetCounter[type.type()]++ & 0xFFFF);
|
||||
}
|
||||
|
||||
uint16_t currentPacketId(const PacketTypeInfo &type){
|
||||
return static_cast<uint16_t>(data->packetCounter[type.type()] & 0xFFFF);
|
||||
}
|
||||
|
||||
uint16_t generationId(const PacketTypeInfo &type){
|
||||
return static_cast<uint16_t>((data->packetCounter[type.type()] >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
memset(&data->packetCounter[0], 0, sizeof(uint32_t) * 16);
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<PacketIdManagerData> data;
|
||||
};
|
||||
|
||||
namespace PacketFlag {
|
||||
enum PacketFlag : uint8_t {
|
||||
None = 0x00,
|
||||
Fragmented = 0x10, //If packet type voice then its toggle the CELT Mono
|
||||
NewProtocol = 0x20,
|
||||
Compressed = 0x40, //If packet type voice than its the header
|
||||
Unencrypted = 0x80
|
||||
};
|
||||
typedef uint8_t PacketFlags;
|
||||
|
||||
std::string to_string(PacketFlag flag);
|
||||
}
|
||||
|
||||
#define MAC_SIZE 8
|
||||
#define SERVER_HEADER_SIZE 3
|
||||
#define CLIENT_HEADER_SIZE 5
|
||||
|
||||
class BasicPacket {
|
||||
public:
|
||||
explicit BasicPacket(size_t header_length, size_t data_length);
|
||||
virtual ~BasicPacket();
|
||||
|
||||
BasicPacket(const BasicPacket&) = delete;
|
||||
BasicPacket(BasicPacket&&) = delete;
|
||||
|
||||
virtual uint16_t packetId() const = 0;
|
||||
virtual uint16_t generationId() const = 0;
|
||||
virtual PacketTypeInfo type() const = 0;
|
||||
|
||||
/* packet flag info */
|
||||
inline bool has_flag(PacketFlag::PacketFlag flag) const { return this->_flags_type_byte() & flag; }
|
||||
inline uint8_t flag_mask() const { return this->_flags_type_byte(); };
|
||||
[[nodiscard]] std::string flags() const;
|
||||
|
||||
/* manipulate flags */
|
||||
inline void set_flags(PacketFlag::PacketFlags flags) {
|
||||
uint8_t& byte = this->_flags_type_byte();
|
||||
byte &= 0xF; /* clear all flags */
|
||||
byte |= (flags & 0xF0);
|
||||
}
|
||||
inline void enable_flag(PacketFlag::PacketFlag flag){ this->toggle_flag(flag, true); }
|
||||
inline void toggle_flag(PacketFlag::PacketFlag flag, bool state) {
|
||||
if(state)
|
||||
this->_flags_type_byte() |= flag;
|
||||
else
|
||||
this->_flags_type_byte() &= (uint8_t) ~flag;
|
||||
}
|
||||
|
||||
virtual void applyPacketId(PacketIdManager &);
|
||||
virtual void applyPacketId(uint16_t, uint16_t);
|
||||
|
||||
void setListener(std::unique_ptr<threads::Future<bool>> listener){
|
||||
if(!this->type().requireAcknowledge())
|
||||
throw std::logic_error("Packet type does not support a acknowledge listener!");
|
||||
this->listener = std::move(listener);
|
||||
}
|
||||
inline std::unique_ptr<threads::Future<bool>>& getListener() { return this->listener; }
|
||||
|
||||
inline size_t length() const { return this->_buffer.length(); }
|
||||
inline const pipes::buffer_view mac() const { return this->_buffer.view(0, MAC_SIZE); }
|
||||
inline pipes::buffer mac() { return this->_buffer.range(0, MAC_SIZE); }
|
||||
inline size_t mac_length() const { return MAC_SIZE; }
|
||||
|
||||
inline const pipes::buffer_view header() const { return this->_buffer.view(MAC_SIZE, this->_header_length); }
|
||||
inline pipes::buffer header() { return this->_buffer.range(MAC_SIZE, this->_header_length); }
|
||||
inline size_t header_length() const { return this->_header_length; }
|
||||
|
||||
inline size_t data_length() const { return this->_buffer.length() - (MAC_SIZE + this->_header_length); }
|
||||
inline const pipes::buffer_view data() const { return this->_buffer.view(MAC_SIZE + this->_header_length); }
|
||||
inline pipes::buffer data() { return this->_buffer.range(MAC_SIZE + this->_header_length); }
|
||||
|
||||
void append_data(const std::vector<pipes::buffer> &data);
|
||||
|
||||
inline void data(const pipes::buffer_view &data){
|
||||
this->_buffer.resize(MAC_SIZE + this->_header_length + data.length());
|
||||
memcpy((char*) this->_buffer.data_ptr() + MAC_SIZE + this->_header_length, data.data_ptr(), data.length());
|
||||
}
|
||||
|
||||
inline void mac(const pipes::buffer_view &_new){
|
||||
assert(_new.length() >= MAC_SIZE);
|
||||
memcpy(this->_buffer.data_ptr(), _new.data_ptr(), MAC_SIZE);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool isEncrypted() const { return this->memory_state.encrypted; }
|
||||
inline void setEncrypted(bool flag){ this->memory_state.encrypted = flag; }
|
||||
|
||||
[[nodiscard]] inline bool isCompressed() const { return this->memory_state.compressed; }
|
||||
inline void setCompressed(bool flag){ this->memory_state.compressed = flag; }
|
||||
|
||||
[[nodiscard]] inline bool isFragmentEntry() const { return this->memory_state.fragment_entry; }
|
||||
inline void setFragmentedEntry(bool flag){ this->memory_state.fragment_entry = flag; }
|
||||
|
||||
Command asCommand();
|
||||
|
||||
//Has the size of a byte
|
||||
union {
|
||||
#ifdef WIN32
|
||||
__pragma(pack(push, 1))
|
||||
#endif
|
||||
struct {
|
||||
bool encrypted: 1;
|
||||
bool compressed: 1;
|
||||
bool fragment_entry: 1;
|
||||
|
||||
bool id_branded: 1;
|
||||
}
|
||||
#ifdef WIN32
|
||||
__pragma(pack(pop));
|
||||
#else
|
||||
__attribute__((packed));
|
||||
#endif
|
||||
|
||||
uint8_t flags = 0;
|
||||
} memory_state;
|
||||
|
||||
pipes::buffer buffer() { return this->_buffer; }
|
||||
void buffer(pipes::buffer buffer) {
|
||||
assert(buffer.length() >= this->_header_length + MAC_SIZE);
|
||||
this->_buffer = std::move(buffer);
|
||||
}
|
||||
protected:
|
||||
BasicPacket() = default;
|
||||
|
||||
virtual const uint8_t& _flags_type_byte() const = 0;
|
||||
virtual uint8_t& _flags_type_byte() = 0;
|
||||
|
||||
virtual void setPacketId(uint16_t, uint16_t) = 0;
|
||||
uint8_t _header_length;
|
||||
pipes::buffer _buffer;
|
||||
|
||||
uint16_t genId = 0;
|
||||
std::unique_ptr<threads::Future<bool>> listener;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Packet from the client
|
||||
*/
|
||||
class ClientPacket : public BasicPacket {
|
||||
friend std::unique_ptr<ClientPacket> std::make_unique<ClientPacket>();
|
||||
public:
|
||||
static constexpr size_t META_MAC_SIZE = 8;
|
||||
static constexpr size_t META_HEADER_SIZE = CLIENT_HEADER_SIZE;
|
||||
static constexpr size_t META_SIZE = META_MAC_SIZE + META_HEADER_SIZE;
|
||||
|
||||
[[nodiscard]] static std::unique_ptr<ClientPacket> from_buffer(const pipes::buffer_view& buffer);
|
||||
|
||||
ClientPacket(const PacketTypeInfo& type, const pipes::buffer_view& data);
|
||||
ClientPacket(const PacketTypeInfo& type, uint8_t flag_mask, const pipes::buffer_view& data);
|
||||
~ClientPacket() override;
|
||||
ClientPacket(const ClientPacket&) = delete;
|
||||
ClientPacket(ClientPacket&&) = delete;
|
||||
|
||||
uint16_t clientId() const;
|
||||
void clientId(uint16_t);
|
||||
|
||||
uint16_t packetId() const override;
|
||||
|
||||
uint16_t generationId() const override;
|
||||
void generationId(uint16_t generation) { this->genId = generation; }
|
||||
|
||||
PacketTypeInfo type() const override;
|
||||
void type(const PacketTypeInfo&);
|
||||
|
||||
private:
|
||||
ClientPacket() = default;
|
||||
|
||||
const uint8_t &_flags_type_byte() const override {
|
||||
return this->header().data_ptr<uint8_t>()[4];
|
||||
}
|
||||
|
||||
uint8_t &_flags_type_byte() override {
|
||||
return this->header().data_ptr<uint8_t>()[4];
|
||||
}
|
||||
|
||||
void setPacketId(uint16_t, uint16_t) override;
|
||||
};
|
||||
|
||||
class ClientPacketParser {
|
||||
public:
|
||||
constexpr static auto kHeaderOffset = 8;
|
||||
constexpr static auto kHeaderLength = CLIENT_HEADER_SIZE;
|
||||
|
||||
constexpr static auto kPayloadOffset = kHeaderOffset + CLIENT_HEADER_SIZE;
|
||||
explicit ClientPacketParser(pipes::buffer_view buffer) : _buffer{std::move(buffer)} {}
|
||||
ClientPacketParser(const ClientPacketParser&) = delete;
|
||||
|
||||
[[nodiscard]] inline bool valid() const {
|
||||
if(this->_buffer.length() < kPayloadOffset) return false;
|
||||
return this->type() <= 8;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* data_ptr() const { return this->_buffer.data_ptr(); }
|
||||
[[nodiscard]] inline void* mutable_data_ptr() { return (void*) this->_buffer.data_ptr(); }
|
||||
|
||||
[[nodiscard]] inline pipes::buffer_view buffer() const { return this->_buffer; }
|
||||
[[nodiscard]] inline pipes::buffer_view mac() const { return this->_buffer.view(0, 8); }
|
||||
[[nodiscard]] inline pipes::buffer_view payload() const { return this->_buffer.view(kPayloadOffset); }
|
||||
[[nodiscard]] inline size_t payload_length() const { return this->_buffer.length() - kPayloadOffset; }
|
||||
|
||||
[[nodiscard]] uint16_t client_id() const;
|
||||
[[nodiscard]] uint16_t packet_id() const;
|
||||
[[nodiscard]] uint8_t type() const;
|
||||
[[nodiscard]] uint8_t flags() const;
|
||||
|
||||
[[nodiscard]] bool is_encrypted() const;
|
||||
[[nodiscard]] bool is_compressed() const;
|
||||
[[nodiscard]] bool is_fragmented() const;
|
||||
|
||||
[[nodiscard]] uint16_t estimated_generation() const { return this->generation; }
|
||||
void set_estimated_generation(uint16_t gen) { this->generation = gen; }
|
||||
|
||||
inline void set_decrypted() { this->decrypted = true; }
|
||||
inline void set_uncompressed() { this->uncompressed = true; }
|
||||
inline void set_defragmented() { this->defragmented = true; }
|
||||
private:
|
||||
uint16_t generation{};
|
||||
bool decrypted{false}, uncompressed{false}, defragmented{false};
|
||||
pipes::buffer_view _buffer{};
|
||||
};
|
||||
|
||||
/**
|
||||
* Packet from the server
|
||||
*/
|
||||
class ServerPacket : public BasicPacket {
|
||||
friend std::unique_ptr<ServerPacket> std::make_unique<ServerPacket>();
|
||||
public:
|
||||
static constexpr size_t META_MAC_SIZE = 8;
|
||||
static constexpr size_t META_HEADER_SIZE = SERVER_HEADER_SIZE;
|
||||
static constexpr size_t META_SIZE = META_MAC_SIZE + META_HEADER_SIZE;
|
||||
|
||||
[[nodiscard]] static std::unique_ptr<ServerPacket> from_buffer(const pipes::buffer_view& buffer);
|
||||
|
||||
ServerPacket(uint8_t flagMask, const pipes::buffer_view& data);
|
||||
ServerPacket(const PacketTypeInfo& type, const pipes::buffer_view& data);
|
||||
ServerPacket(PacketTypeInfo type, size_t /* data length */);
|
||||
~ServerPacket() override;
|
||||
|
||||
ServerPacket(const ServerPacket&) = delete;
|
||||
ServerPacket(ServerPacket&&) = delete;
|
||||
|
||||
[[nodiscard]] uint16_t packetId() const override;
|
||||
[[nodiscard]] uint16_t generationId() const override;
|
||||
void generationId(uint16_t generation) { this->genId = generation; }
|
||||
[[nodiscard]] PacketTypeInfo type() const override;
|
||||
|
||||
private:
|
||||
ServerPacket() = default;
|
||||
|
||||
[[nodiscard]] const uint8_t &_flags_type_byte() const override {
|
||||
return this->header().data_ptr<uint8_t>()[2];
|
||||
}
|
||||
|
||||
uint8_t &_flags_type_byte() override {
|
||||
return this->header().data_ptr<uint8_t>()[2];
|
||||
}
|
||||
|
||||
void setPacketId(uint16_t, uint16_t) override;
|
||||
};
|
||||
}
|
||||
}
|
@ -1,220 +1,220 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef byte
|
||||
#define byte asdd
|
||||
#ifndef WIN32
|
||||
#warning The byte macro is already defined! Undefining it!
|
||||
#endif
|
||||
#undef byte
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <pipes/buffer.h>
|
||||
#include "../Variable.h"
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
#include <json/json.h>
|
||||
#endif
|
||||
|
||||
namespace ts {
|
||||
#define PARM_TYPE(type, fromString, toString) \
|
||||
BaseCommandParm(std::string key, type value) : BaseCommandParm(std::pair<std::string, std::string>(key, "")) {\
|
||||
toString; \
|
||||
} \
|
||||
BaseCommandParm& operator=(type value){ \
|
||||
toString; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
operator type(){ \
|
||||
fromString; \
|
||||
}
|
||||
|
||||
class Command;
|
||||
class ValueList;
|
||||
|
||||
|
||||
//PARM_TYPE(ts::Property, return ts::Property(nullptr, key(), value(), 0), f_value() = value.value());
|
||||
|
||||
class ParameterBulk {
|
||||
friend class Command;
|
||||
friend class ValueList;
|
||||
public:
|
||||
ParameterBulk(const ParameterBulk& ref) : parms(ref.parms) {}
|
||||
|
||||
|
||||
variable operator[](size_t index){
|
||||
if(parms.size() > index) return parms[index];
|
||||
return variable{"", "", VARTYPE_NULL};
|
||||
}
|
||||
|
||||
const variable& operator[](const std::string& key) const {
|
||||
for(const auto& elm : parms)
|
||||
if(elm.key() == key){
|
||||
return elm;
|
||||
}
|
||||
|
||||
throw std::invalid_argument("could not find key [" + key + "]");
|
||||
}
|
||||
|
||||
variable& operator[](const std::string& key) {
|
||||
for(auto& elm : parms)
|
||||
if(elm.key() == key){
|
||||
return elm;
|
||||
}
|
||||
this->parms.push_back(variable(key, "", VariableType::VARTYPE_NULL));
|
||||
return this->operator[](key);
|
||||
}
|
||||
|
||||
bool has(const std::string& key) const {
|
||||
for(const auto& elm : parms)
|
||||
if(elm.key() == key && elm.type() != VariableType::VARTYPE_NULL) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::deque<std::string> keys() const {
|
||||
std::deque<std::string> result;
|
||||
for(const auto& elm : parms)
|
||||
result.push_back(elm.key());
|
||||
return result;
|
||||
}
|
||||
|
||||
ParameterBulk& operator=(const ParameterBulk& ref){
|
||||
parms = ref.parms;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
ParameterBulk() {}
|
||||
ParameterBulk(std::deque<variable> p) : parms(p) {}
|
||||
std::deque<variable> parms;
|
||||
};
|
||||
|
||||
class ValueList {
|
||||
friend class Command;
|
||||
public:
|
||||
ValueList() = delete;
|
||||
ValueList(const ValueList& ref) : key(ref.key), bulkList(ref.bulkList) {}
|
||||
|
||||
variable operator[](int index){
|
||||
while(index >= bulkList.size()) bulkList.push_back(ParameterBulk());
|
||||
return bulkList[index][key];
|
||||
}
|
||||
|
||||
variable first() const {
|
||||
int index = 0;
|
||||
while(index < bulkList.size() && !bulkList[index].has(key)) index++;
|
||||
if(index < bulkList.size()) return bulkList[index][key];
|
||||
|
||||
return variable{this->key, "", VariableType::VARTYPE_NULL};
|
||||
throw std::invalid_argument("could not find key [" + key + "]");
|
||||
}
|
||||
|
||||
size_t size(){
|
||||
size_t count = 0;
|
||||
for(const auto& blk : this->bulkList)
|
||||
if(blk.has(this->key)) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ValueList& operator=(T var){ operator[](0) = var; return *this; }
|
||||
ValueList& operator=(ts::ValueList& var){ operator[](0) = var.first().value(); return *this; }
|
||||
|
||||
|
||||
template <typename T>
|
||||
T as() const { return first().as<T>(); }
|
||||
|
||||
template <typename T>
|
||||
operator T() { return as<T>(); }
|
||||
|
||||
template <typename T>
|
||||
bool operator==(T other){ return as<T>() == other; }
|
||||
template <typename T>
|
||||
bool operator!=(T other){ return as<T>() != other; }
|
||||
|
||||
std::string string() const { return as<std::string>(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream&, const ValueList&);
|
||||
private:
|
||||
ValueList(std::string& key, std::deque<ParameterBulk>& bulkList) : key(key), bulkList(bulkList) {}
|
||||
std::string key;
|
||||
public:
|
||||
std::deque<ParameterBulk>& bulkList;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream,const ValueList& list) {
|
||||
stream << "{ Key: " << list.key << " = [";
|
||||
for(auto it = list.bulkList.begin(); it != list.bulkList.end(); it++)
|
||||
if(it->has(list.key)) {
|
||||
stream << (*it)[list.key].value();
|
||||
if(it + 1 != list.bulkList.end())
|
||||
stream << ", ";
|
||||
}
|
||||
stream << "]}";
|
||||
return stream;
|
||||
}
|
||||
|
||||
class Command {
|
||||
public:
|
||||
static Command parse(const pipes::buffer_view& buffer, bool expect_command = true, bool drop_non_utf8 = false);
|
||||
|
||||
explicit Command(const std::string& command);
|
||||
explicit Command(const std::string& command, std::initializer_list<variable>);
|
||||
explicit Command(const std::string& command, std::initializer_list<std::initializer_list<variable>>);
|
||||
|
||||
Command(const Command&);
|
||||
~Command();
|
||||
|
||||
inline std::string command() const { return getCommand(); }
|
||||
std::string getCommand() const { return _command; }
|
||||
|
||||
std::string build(bool escaped = true) const;
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
Json::Value buildJson() const;
|
||||
#endif
|
||||
|
||||
const ParameterBulk& operator[](size_t index) const {
|
||||
if(bulks.size() <= index) throw std::invalid_argument("got out of length");
|
||||
return bulks[index];
|
||||
}
|
||||
|
||||
ParameterBulk& operator[](size_t index){
|
||||
while(bulks.size() <= index) bulks.push_back(ParameterBulk{});
|
||||
return bulks[index];
|
||||
}
|
||||
|
||||
ValueList operator[](std::string key){
|
||||
return ValueList(key, bulks);
|
||||
}
|
||||
|
||||
size_t bulkCount() const { return bulks.size(); }
|
||||
void pop_bulk();
|
||||
void push_bulk_front();
|
||||
|
||||
bool hasParm(std::string);
|
||||
void clear_parameters() { this->paramethers.clear(); }
|
||||
std::deque<std::string> parms();
|
||||
void enableParm(const std::string& key){ toggleParm(key, true); }
|
||||
void disableParm(const std::string& key){ toggleParm(key, false); }
|
||||
void toggleParm(const std::string& key, bool flag);
|
||||
|
||||
void reverseBulks();
|
||||
private:
|
||||
Command();
|
||||
|
||||
std::string _command;
|
||||
std::deque<ParameterBulk> bulks;
|
||||
std::deque<std::string> paramethers;
|
||||
};
|
||||
}
|
||||
|
||||
DEFINE_VARIABLE_TRANSFORM_TO_STR(ts::ValueList, in.string());
|
||||
DEFINE_VARIABLE_TRANSFORM_TYPE(ts::ValueList, VARTYPE_TEXT);
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef byte
|
||||
#define byte asdd
|
||||
#ifndef WIN32
|
||||
#warning The byte macro is already defined! Undefining it!
|
||||
#endif
|
||||
#undef byte
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <pipes/buffer.h>
|
||||
#include "../Variable.h"
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
#include <json/json.h>
|
||||
#endif
|
||||
|
||||
namespace ts {
|
||||
#define PARM_TYPE(type, fromString, toString) \
|
||||
BaseCommandParm(std::string key, type value) : BaseCommandParm(std::pair<std::string, std::string>(key, "")) {\
|
||||
toString; \
|
||||
} \
|
||||
BaseCommandParm& operator=(type value){ \
|
||||
toString; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
operator type(){ \
|
||||
fromString; \
|
||||
}
|
||||
|
||||
class Command;
|
||||
class ValueList;
|
||||
|
||||
|
||||
//PARM_TYPE(ts::Property, return ts::Property(nullptr, key(), value(), 0), f_value() = value.value());
|
||||
|
||||
class ParameterBulk {
|
||||
friend class Command;
|
||||
friend class ValueList;
|
||||
public:
|
||||
ParameterBulk(const ParameterBulk& ref) : parms(ref.parms) {}
|
||||
|
||||
|
||||
variable operator[](size_t index){
|
||||
if(parms.size() > index) return parms[index];
|
||||
return variable{"", "", VARTYPE_NULL};
|
||||
}
|
||||
|
||||
const variable& operator[](const std::string& key) const {
|
||||
for(const auto& elm : parms)
|
||||
if(elm.key() == key){
|
||||
return elm;
|
||||
}
|
||||
|
||||
throw std::invalid_argument("could not find key [" + key + "]");
|
||||
}
|
||||
|
||||
variable& operator[](const std::string& key) {
|
||||
for(auto& elm : parms)
|
||||
if(elm.key() == key){
|
||||
return elm;
|
||||
}
|
||||
this->parms.push_back(variable(key, "", VariableType::VARTYPE_NULL));
|
||||
return this->operator[](key);
|
||||
}
|
||||
|
||||
bool has(const std::string& key) const {
|
||||
for(const auto& elm : parms)
|
||||
if(elm.key() == key && elm.type() != VariableType::VARTYPE_NULL) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::deque<std::string> keys() const {
|
||||
std::deque<std::string> result;
|
||||
for(const auto& elm : parms)
|
||||
result.push_back(elm.key());
|
||||
return result;
|
||||
}
|
||||
|
||||
ParameterBulk& operator=(const ParameterBulk& ref){
|
||||
parms = ref.parms;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
ParameterBulk() {}
|
||||
ParameterBulk(std::deque<variable> p) : parms(p) {}
|
||||
std::deque<variable> parms;
|
||||
};
|
||||
|
||||
class ValueList {
|
||||
friend class Command;
|
||||
public:
|
||||
ValueList() = delete;
|
||||
ValueList(const ValueList& ref) : key(ref.key), bulkList(ref.bulkList) {}
|
||||
|
||||
variable operator[](int index){
|
||||
while(index >= bulkList.size()) bulkList.push_back(ParameterBulk());
|
||||
return bulkList[index][key];
|
||||
}
|
||||
|
||||
variable first() const {
|
||||
int index = 0;
|
||||
while(index < bulkList.size() && !bulkList[index].has(key)) index++;
|
||||
if(index < bulkList.size()) return bulkList[index][key];
|
||||
|
||||
return variable{this->key, "", VariableType::VARTYPE_NULL};
|
||||
throw std::invalid_argument("could not find key [" + key + "]");
|
||||
}
|
||||
|
||||
size_t size(){
|
||||
size_t count = 0;
|
||||
for(const auto& blk : this->bulkList)
|
||||
if(blk.has(this->key)) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ValueList& operator=(T var){ operator[](0) = var; return *this; }
|
||||
ValueList& operator=(ts::ValueList& var){ operator[](0) = var.first().value(); return *this; }
|
||||
|
||||
|
||||
template <typename T>
|
||||
T as() const { return first().as<T>(); }
|
||||
|
||||
template <typename T>
|
||||
operator T() { return as<T>(); }
|
||||
|
||||
template <typename T>
|
||||
bool operator==(T other){ return as<T>() == other; }
|
||||
template <typename T>
|
||||
bool operator!=(T other){ return as<T>() != other; }
|
||||
|
||||
std::string string() const { return as<std::string>(); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream&, const ValueList&);
|
||||
private:
|
||||
ValueList(std::string& key, std::deque<ParameterBulk>& bulkList) : key(key), bulkList(bulkList) {}
|
||||
std::string key;
|
||||
public:
|
||||
std::deque<ParameterBulk>& bulkList;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream,const ValueList& list) {
|
||||
stream << "{ Key: " << list.key << " = [";
|
||||
for(auto it = list.bulkList.begin(); it != list.bulkList.end(); it++)
|
||||
if(it->has(list.key)) {
|
||||
stream << (*it)[list.key].value();
|
||||
if(it + 1 != list.bulkList.end())
|
||||
stream << ", ";
|
||||
}
|
||||
stream << "]}";
|
||||
return stream;
|
||||
}
|
||||
|
||||
class Command {
|
||||
public:
|
||||
static Command parse(const pipes::buffer_view& buffer, bool expect_command = true, bool drop_non_utf8 = false);
|
||||
|
||||
explicit Command(const std::string& command);
|
||||
explicit Command(const std::string& command, std::initializer_list<variable>);
|
||||
explicit Command(const std::string& command, std::initializer_list<std::initializer_list<variable>>);
|
||||
|
||||
Command(const Command&);
|
||||
~Command();
|
||||
|
||||
inline std::string command() const { return getCommand(); }
|
||||
std::string getCommand() const { return _command; }
|
||||
|
||||
std::string build(bool escaped = true) const;
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
Json::Value buildJson() const;
|
||||
#endif
|
||||
|
||||
const ParameterBulk& operator[](size_t index) const {
|
||||
if(bulks.size() <= index) throw std::invalid_argument("got out of length");
|
||||
return bulks[index];
|
||||
}
|
||||
|
||||
ParameterBulk& operator[](size_t index){
|
||||
while(bulks.size() <= index) bulks.push_back(ParameterBulk{});
|
||||
return bulks[index];
|
||||
}
|
||||
|
||||
ValueList operator[](std::string key){
|
||||
return ValueList(key, bulks);
|
||||
}
|
||||
|
||||
size_t bulkCount() const { return bulks.size(); }
|
||||
void pop_bulk();
|
||||
void push_bulk_front();
|
||||
|
||||
bool hasParm(std::string);
|
||||
void clear_parameters() { this->paramethers.clear(); }
|
||||
std::deque<std::string> parms();
|
||||
void enableParm(const std::string& key){ toggleParm(key, true); }
|
||||
void disableParm(const std::string& key){ toggleParm(key, false); }
|
||||
void toggleParm(const std::string& key, bool flag);
|
||||
|
||||
void reverseBulks();
|
||||
private:
|
||||
Command();
|
||||
|
||||
std::string _command;
|
||||
std::deque<ParameterBulk> bulks;
|
||||
std::deque<std::string> paramethers;
|
||||
};
|
||||
}
|
||||
|
||||
DEFINE_VARIABLE_TRANSFORM_TO_STR(ts::ValueList, in.string());
|
||||
DEFINE_VARIABLE_TRANSFORM_TYPE(ts::ValueList, VARTYPE_TEXT);
|
||||
|
||||
#undef PARM_TYPE
|
File diff suppressed because it is too large
Load Diff
@ -1,74 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <condition_variable>
|
||||
#include "sql/SqlQuery.h"
|
||||
|
||||
#include "../../misc/spin_lock.h"
|
||||
#include <mysql.h>
|
||||
|
||||
#define ERROR_MYSQL_MISSING_DRIVER -1
|
||||
#define ERROR_MYSQL_INVLID_CONNECT -2
|
||||
#define ERROR_MYSQL_INVLID_PROPERTIES -3
|
||||
#define ERROR_MYSQL_INVLID_URL -4
|
||||
|
||||
namespace sql::mysql {
|
||||
class MySQLManager;
|
||||
|
||||
bool evaluate_sql_query(std::string& sql, const std::vector<variable>& vars, std::vector<variable>& result);
|
||||
|
||||
class MySQLCommand : public CommandData { };
|
||||
|
||||
struct Connection {
|
||||
MYSQL* handle = nullptr;
|
||||
|
||||
spin_lock used_lock;
|
||||
bool used = false;
|
||||
|
||||
~Connection();
|
||||
};
|
||||
|
||||
struct AcquiredConnection {
|
||||
MySQLManager* owner;
|
||||
std::shared_ptr<Connection> connection;
|
||||
|
||||
AcquiredConnection(MySQLManager* owner, std::shared_ptr<Connection> );
|
||||
~AcquiredConnection();
|
||||
};
|
||||
|
||||
class MySQLManager : public SqlManager {
|
||||
friend struct AcquiredConnection;
|
||||
public:
|
||||
//typedef std::function<void(const std::shared_ptr<ConnectionEntry>&)> ListenerConnectionDisconnect;
|
||||
//typedef std::function<void(const std::shared_ptr<ConnectionEntry>&)> ListenerConnectionCreated;
|
||||
|
||||
typedef std::function<void()> ListenerConnected;
|
||||
typedef std::function<void(bool /* wanted */)> ListenerDisconnected;
|
||||
|
||||
MySQLManager();
|
||||
virtual ~MySQLManager();
|
||||
|
||||
result connect(const std::string &string) override;
|
||||
bool connected() override;
|
||||
result disconnect() override;
|
||||
|
||||
ListenerDisconnected listener_disconnected;
|
||||
protected:
|
||||
std::shared_ptr<CommandData> copyCommandData(std::shared_ptr<CommandData> ptr) override;
|
||||
std::shared_ptr<CommandData> allocateCommandData() override;
|
||||
result executeCommand(std::shared_ptr<CommandData> ptr) override;
|
||||
result queryCommand(std::shared_ptr<CommandData> ptr, const QueryCallback &fn) override;
|
||||
|
||||
public:
|
||||
std::unique_ptr<AcquiredConnection> next_connection();
|
||||
void connection_closed(const std::shared_ptr<Connection>& /* connection */);
|
||||
|
||||
std::mutex connections_lock;
|
||||
std::condition_variable connections_condition;
|
||||
std::deque<std::shared_ptr<Connection>> connections;
|
||||
|
||||
bool disconnecting = false;
|
||||
};
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <condition_variable>
|
||||
#include "sql/SqlQuery.h"
|
||||
|
||||
#include "../../misc/spin_lock.h"
|
||||
#include <mysql.h>
|
||||
|
||||
#define ERROR_MYSQL_MISSING_DRIVER -1
|
||||
#define ERROR_MYSQL_INVLID_CONNECT -2
|
||||
#define ERROR_MYSQL_INVLID_PROPERTIES -3
|
||||
#define ERROR_MYSQL_INVLID_URL -4
|
||||
|
||||
namespace sql::mysql {
|
||||
class MySQLManager;
|
||||
|
||||
bool evaluate_sql_query(std::string& sql, const std::vector<variable>& vars, std::vector<variable>& result);
|
||||
|
||||
class MySQLCommand : public CommandData { };
|
||||
|
||||
struct Connection {
|
||||
MYSQL* handle = nullptr;
|
||||
|
||||
spin_lock used_lock;
|
||||
bool used = false;
|
||||
|
||||
~Connection();
|
||||
};
|
||||
|
||||
struct AcquiredConnection {
|
||||
MySQLManager* owner;
|
||||
std::shared_ptr<Connection> connection;
|
||||
|
||||
AcquiredConnection(MySQLManager* owner, std::shared_ptr<Connection> );
|
||||
~AcquiredConnection();
|
||||
};
|
||||
|
||||
class MySQLManager : public SqlManager {
|
||||
friend struct AcquiredConnection;
|
||||
public:
|
||||
//typedef std::function<void(const std::shared_ptr<ConnectionEntry>&)> ListenerConnectionDisconnect;
|
||||
//typedef std::function<void(const std::shared_ptr<ConnectionEntry>&)> ListenerConnectionCreated;
|
||||
|
||||
typedef std::function<void()> ListenerConnected;
|
||||
typedef std::function<void(bool /* wanted */)> ListenerDisconnected;
|
||||
|
||||
MySQLManager();
|
||||
virtual ~MySQLManager();
|
||||
|
||||
result connect(const std::string &string) override;
|
||||
bool connected() override;
|
||||
result disconnect() override;
|
||||
|
||||
ListenerDisconnected listener_disconnected;
|
||||
protected:
|
||||
std::shared_ptr<CommandData> copyCommandData(std::shared_ptr<CommandData> ptr) override;
|
||||
std::shared_ptr<CommandData> allocateCommandData() override;
|
||||
result executeCommand(std::shared_ptr<CommandData> ptr) override;
|
||||
result queryCommand(std::shared_ptr<CommandData> ptr, const QueryCallback &fn) override;
|
||||
|
||||
public:
|
||||
std::unique_ptr<AcquiredConnection> next_connection();
|
||||
void connection_closed(const std::shared_ptr<Connection>& /* connection */);
|
||||
|
||||
std::mutex connections_lock;
|
||||
std::condition_variable connections_condition;
|
||||
std::deque<std::shared_ptr<Connection>> connections;
|
||||
|
||||
bool disconnecting = false;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user