Some updates

This commit is contained in:
WolverinDEV 2020-02-15 14:03:32 +01:00
parent 9e2249462c
commit 97fd71b69a
11 changed files with 5206 additions and 5206 deletions

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
};
}
}

View File

@ -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

View File

@ -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;
};
}