Made all non required libraries for the client optional
This commit is contained in:
parent
ac48d30696
commit
6e2d901bf6
259
CMakeLists.txt
259
CMakeLists.txt
@ -2,16 +2,6 @@ cmake_minimum_required(VERSION 3.6)
|
|||||||
project(TeaSpeak-Shared)
|
project(TeaSpeak-Shared)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
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 "")
|
if(CMAKE_PLATFORM_INCLUDE AND NOT CMAKE_PLATFORM_INCLUDE STREQUAL "")
|
||||||
include(${CMAKE_PLATFORM_INCLUDE})
|
include(${CMAKE_PLATFORM_INCLUDE})
|
||||||
endif()
|
endif()
|
||||||
@ -25,47 +15,69 @@ include_directories(${TomCrypt_INCLUDE_DIR})
|
|||||||
find_package(DataPipes REQUIRED)
|
find_package(DataPipes REQUIRED)
|
||||||
include_directories(${DataPipes_INCLUDE_DIR})
|
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)
|
find_package(Ed25519 REQUIRED)
|
||||||
include_directories(${ed25519_INCLUDE_DIR})
|
include_directories(${ed25519_INCLUDE_DIR})
|
||||||
|
|
||||||
find_package(ThreadPool REQUIRED)
|
set(TARGET_LIBRARIES)
|
||||||
include_directories(${ThreadPool_INCLUDE_DIR})
|
set(FEATURE_LOGGING ON)
|
||||||
if(WIN32)
|
set(FEATURE_DATABASE ON)
|
||||||
add_definitions(-DWINDOWS) #Required for ThreadPool
|
|
||||||
|
find_package(ThreadPool)
|
||||||
|
if(ThreadPool_FOUND)
|
||||||
|
include_directories(${ThreadPool_INCLUDE_DIR})
|
||||||
|
if(WIN32)
|
||||||
|
add_definitions(-DWINDOWS) #Required for ThreadPool
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message("Missing ThreadPool. Skipping database support.")
|
||||||
|
set(FEATURE_DATABASE OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(StringVariable)
|
||||||
|
if(StringVariable_FOUND)
|
||||||
|
include_directories(${StringVariable_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
message("Missing StringVariable. Disabling logging support")
|
||||||
|
set(FEATURE_LOGGING OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(spdlog)
|
||||||
|
if(spdlog_FOUND)
|
||||||
|
#Its a header only lib so we should be fine :)
|
||||||
|
list(APPEND TARGET_LIBRARIES spdlog::spdlog_header_only)
|
||||||
|
else()
|
||||||
|
message("Missing spdlog. Disabling logging support")
|
||||||
|
set(FEATURE_LOGGING OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(CXXTerminal)
|
||||||
|
if(CXXTerminal_FOUND)
|
||||||
|
add_definitions(-DHAVE_CXX_TERMINAL)
|
||||||
|
else()
|
||||||
|
message("Missing CXXTerminal. Disabling logging support")
|
||||||
|
set(FEATURE_LOGGING OFF)
|
||||||
endif()
|
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)
|
if(NOT TEASPEAK_SERVER)
|
||||||
add_definitions(-DNO_OPEN_SSL)
|
add_definitions(-DNO_OPEN_SSL)
|
||||||
add_definitions(-D_HAS_STD_BYTE)
|
add_definitions(-D_HAS_STD_BYTE)
|
||||||
#FML
|
#FML
|
||||||
else()
|
else()
|
||||||
find_package(CXXTerminal REQUIRED)
|
|
||||||
|
|
||||||
add_definitions(-DHAVE_CXX_TERMINAL)
|
|
||||||
add_definitions(-DHAVE_JSON)
|
|
||||||
set(HAVE_SQLITE3 ON)
|
set(HAVE_SQLITE3 ON)
|
||||||
set(HAVE_OPEN_SSL ON)
|
set(HAVE_OPEN_SSL ON)
|
||||||
message("HAVE JSON!")
|
endif()
|
||||||
|
|
||||||
|
if(FEATURE_DATABASE)
|
||||||
|
if(NOT FEATURE_LOGGING)
|
||||||
|
message("Disabling database support because logging support is omitted")
|
||||||
|
set(FEATURE_DATABASE OFF)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
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.
|
||||||
|
|
||||||
set(CompilerFlags
|
set(CompilerFlags
|
||||||
CMAKE_CXX_FLAGS
|
CMAKE_CXX_FLAGS
|
||||||
CMAKE_CXX_FLAGS_DEBUG
|
CMAKE_CXX_FLAGS_DEBUG
|
||||||
@ -81,26 +93,20 @@ if (MSVC)
|
|||||||
endforeach()
|
endforeach()
|
||||||
add_compile_options("/EHsc") #We require exception handling
|
add_compile_options("/EHsc") #We require exception handling
|
||||||
else()
|
else()
|
||||||
|
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)
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3") #-DNDEBUG We want assert!
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3") #-DNDEBUG We want assert!
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO: Reenable for the TeaClient!
|
|
||||||
#add_definitions(-DUSE_BORINGSSL)
|
|
||||||
#include_directories(${LIBRARY_PATH}/boringssl/include/)
|
|
||||||
|
|
||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
src/misc/rnd.cpp
|
src/misc/rnd.cpp
|
||||||
src/misc/duration_utils.cpp
|
src/misc/duration_utils.cpp
|
||||||
src/misc/memtracker.cpp
|
|
||||||
src/misc/digest.cpp
|
src/misc/digest.cpp
|
||||||
src/misc/base64.cpp
|
src/misc/base64.cpp
|
||||||
src/misc/net.cpp
|
src/misc/net.cpp
|
||||||
|
|
||||||
src/lock/rw_mutex.cpp
|
src/lock/rw_mutex.cpp
|
||||||
|
|
||||||
#Logger
|
|
||||||
src/log/LogUtils.cpp
|
|
||||||
src/log/LogSinks.cpp
|
|
||||||
src/qlz/QuickLZ.cpp
|
src/qlz/QuickLZ.cpp
|
||||||
src/converters/converter.cpp
|
src/converters/converter.cpp
|
||||||
|
|
||||||
@ -113,12 +119,12 @@ set(SOURCE_FILES
|
|||||||
src/protocol/Packet.cpp
|
src/protocol/Packet.cpp
|
||||||
src/protocol/buffers.cpp
|
src/protocol/buffers.cpp
|
||||||
src/protocol/buffers_allocator_c.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/CryptHandler.cpp
|
||||||
src/protocol/CompressionHandler.cpp
|
src/protocol/CompressionHandler.cpp
|
||||||
|
|
||||||
|
src/PermissionManager.cpp
|
||||||
|
src/Properties.cpp
|
||||||
|
src/Error.cpp
|
||||||
src/Variable.cpp
|
src/Variable.cpp
|
||||||
src/linked_helper.cpp
|
src/linked_helper.cpp
|
||||||
src/EventLoop.cpp
|
src/EventLoop.cpp
|
||||||
@ -147,16 +153,12 @@ set(HEADER_FILES
|
|||||||
src/misc/lambda.h
|
src/misc/lambda.h
|
||||||
src/misc/hex.h
|
src/misc/hex.h
|
||||||
src/misc/advanced_mutex.h
|
src/misc/advanced_mutex.h
|
||||||
src/misc/memtracker.h
|
|
||||||
src/misc/strobf.h
|
src/misc/strobf.h
|
||||||
|
|
||||||
src/log/LogUtils.h
|
|
||||||
|
|
||||||
src/PermissionManager.h
|
src/PermissionManager.h
|
||||||
src/protocol/buffers.h
|
src/protocol/buffers.h
|
||||||
src/protocol/Packet.h
|
src/protocol/Packet.h
|
||||||
src/Properties.h
|
src/Properties.h
|
||||||
src/BasicChannel.h
|
|
||||||
src/Definitions.h
|
src/Definitions.h
|
||||||
src/Error.h
|
src/Error.h
|
||||||
src/protocol/CryptHandler.h
|
src/protocol/CryptHandler.h
|
||||||
@ -170,7 +172,28 @@ set(HEADER_FILES
|
|||||||
src/channel/TreeView.h
|
src/channel/TreeView.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(HAVE_SQLITE3)
|
if(FEATURE_LOGGING)
|
||||||
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
|
src/log/LogUtils.cpp
|
||||||
|
src/log/LogSinks.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES ${HEADER_FILES}
|
||||||
|
src/log/LogUtils.h
|
||||||
|
src/log/LogSinks.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-DFEATURE_LOGGING)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FEATURE_LOGGING)
|
||||||
|
set(SOURCE_FILES ${SOURCE_FILES} src/misc/memtracker.cpp)
|
||||||
|
set(HEADER_FILES ${HEADER_FILES} src/misc/memtracker.h)
|
||||||
|
else()
|
||||||
|
message("Missing logging support. Don't build mem tracker")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FEATURE_DATABASE)
|
||||||
set(SOURCE_FILES ${SOURCE_FILES}
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
src/sql/SqlQuery.cpp
|
src/sql/SqlQuery.cpp
|
||||||
src/sql/sqlite/SqliteSQL.cpp
|
src/sql/sqlite/SqliteSQL.cpp
|
||||||
@ -184,30 +207,36 @@ if(HAVE_SQLITE3)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_OPEN_SSL)
|
if(HAVE_OPEN_SSL)
|
||||||
set(SOURCE_FILES ${SOURCE_FILES}
|
set(SOURCE_FILES ${SOURCE_FILES} src/ssl/SSLManager.cpp)
|
||||||
src/ssl/SSLManager.cpp
|
set(HEADER_FILES ${HEADER_FILES} src/ssl/SSLManager.h)
|
||||||
)
|
set(OPENSSL_LIBRARIES openssl::ssl::shared openssl::crypto::shared)
|
||||||
set(HEADER_FILES ${HEADER_FILES}
|
|
||||||
src/ssl/SSLManager.h
|
|
||||||
)
|
|
||||||
set(OPENSSL_LIBRARIES
|
|
||||||
openssl::ssl::shared
|
|
||||||
openssl::crypto::shared)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (TEASPEAK_SERVER)
|
||||||
|
# TODO: Remove such stuff and move it into the server!
|
||||||
|
message("Adding TeaSpeak server only related files")
|
||||||
|
|
||||||
|
|
||||||
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
|
src/BasicChannel.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES ${HEADER_FILES}
|
||||||
|
src/BasicChannel.h
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_library(TeaSpeak STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
add_library(TeaSpeak STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||||
target_link_libraries(TeaSpeak PUBLIC
|
target_link_libraries(TeaSpeak PUBLIC
|
||||||
threadpool::static jsoncpp_lib
|
|
||||||
${OPENSSL_LIBRARIES}
|
|
||||||
tomcrypt::static
|
tomcrypt::static
|
||||||
tommath::static
|
tommath::static
|
||||||
|
${OPENSSL_LIBRARIES}
|
||||||
|
${TARGET_LIBRARIES}
|
||||||
dl
|
dl
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(mysql REQUIRED)
|
find_package(mysql)
|
||||||
set(mysql_FOUND ON)
|
if(mysql)
|
||||||
message("${mysql_FOUND}")
|
|
||||||
if(mysql_FOUND)
|
|
||||||
message("Found MySQL")
|
message("Found MySQL")
|
||||||
target_link_libraries(TeaSpeak PUBLIC
|
target_link_libraries(TeaSpeak PUBLIC
|
||||||
mysql::client::static
|
mysql::client::static
|
||||||
@ -220,101 +249,15 @@ endif()
|
|||||||
if (TEASPEAK_SERVER)
|
if (TEASPEAK_SERVER)
|
||||||
target_link_libraries(TeaSpeak PUBLIC CXXTerminal::static)
|
target_link_libraries(TeaSpeak PUBLIC CXXTerminal::static)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_include_directories(TeaSpeak PUBLIC src/)
|
target_include_directories(TeaSpeak PUBLIC src/)
|
||||||
|
|
||||||
install(TARGETS TeaSpeak
|
install(TARGETS TeaSpeak
|
||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
)
|
)
|
||||||
INSTALL (
|
|
||||||
|
INSTALL(
|
||||||
DIRECTORY ${CMAKE_SOURCE_DIR}/src/
|
DIRECTORY ${CMAKE_SOURCE_DIR}/src/
|
||||||
DESTINATION include
|
DESTINATION include
|
||||||
FILES_MATCHING PATTERN "*.h*"
|
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 test/CommandTest.cpp src/query/command3.cpp src/query/Command.cpp src/query/escape.cpp src/converters/converter.cpp src/Variable.cpp)
|
|
||||||
target_link_libraries(CommandTest DataPipes::core::shared jsoncpp_lib ${glib20_DIR}/lib/x86_64-linux-gnu/libffi.so.7 ${nice_DIR}/lib/libnice.so.10)
|
|
||||||
|
|
||||||
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(SQL2Test test/SQL2Test.cpp src/Variable.cpp src/misc/net.cpp)
|
|
||||||
target_link_libraries(SQL2Test sqlite3)
|
|
||||||
|
|
||||||
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 src/Properties.cpp src/PropertyDefinitions.cpp)
|
|
||||||
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 src/protocol/generation.cpp)
|
|
||||||
target_link_libraries(GenerationTest ${TEST_LIBRARIES})
|
|
||||||
|
|
||||||
add_executable(RW-Lock-Test test/rw_lock.cpp src/lock/rw_mutex.cpp)
|
|
||||||
target_link_libraries(GenerationTest ${TEST_LIBRARIES})
|
|
||||||
|
|
||||||
add_executable(PacketLossTest src/protocol/PacketLossCalculator.cpp test/PacketLossCalculateTest.cpp)
|
|
||||||
target_link_libraries(PacketLossTest)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <sstream>
|
|
||||||
#include <misc/base64.h>
|
#include <misc/base64.h>
|
||||||
#include "query/Command.h"
|
#include "query/Command.h"
|
||||||
#include "misc/digest.h"
|
#include "misc/digest.h"
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <condition_variable>
|
||||||
#include "./log/LogUtils.h"
|
|
||||||
#include "./misc/sassert.h"
|
|
||||||
#include "./EventLoop.h"
|
#include "./EventLoop.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -161,14 +156,13 @@ void EventExecutor::_reassign_thread_names(std::unique_lock<std::mutex> &lock) {
|
|||||||
|
|
||||||
void EventExecutor::_executor(ts::event::EventExecutor *loop) {
|
void EventExecutor::_executor(ts::event::EventExecutor *loop) {
|
||||||
while(true) {
|
while(true) {
|
||||||
sassert(std::addressof(loop->lock) != nullptr);
|
unique_lock lock{loop->lock};
|
||||||
|
|
||||||
unique_lock lock(loop->lock);
|
|
||||||
loop->condition.wait(lock, [&] {
|
loop->condition.wait(lock, [&] {
|
||||||
return loop->should_shutdown || loop->should_adjust || loop->head != nullptr;
|
return loop->should_shutdown || loop->should_adjust || loop->head != nullptr;
|
||||||
});
|
});
|
||||||
if(loop->should_shutdown)
|
if(loop->should_shutdown) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(loop->should_adjust) {
|
if(loop->should_adjust) {
|
||||||
const auto current_threads = loop->_threads.size();
|
const auto current_threads = loop->_threads.size();
|
||||||
@ -201,10 +195,10 @@ void EventExecutor::_executor(ts::event::EventExecutor *loop) {
|
|||||||
auto linked_entry = loop->head;
|
auto linked_entry = loop->head;
|
||||||
loop->head = linked_entry->next;
|
loop->head = linked_entry->next;
|
||||||
if(loop->head) {
|
if(loop->head) {
|
||||||
sassert(linked_entry == loop->head->previous);
|
assert(linked_entry == loop->head->previous);
|
||||||
loop->head->previous = nullptr;
|
loop->head->previous = nullptr;
|
||||||
} else {
|
} else {
|
||||||
sassert(linked_entry == loop->tail);
|
assert(linked_entry == loop->tail);
|
||||||
loop->tail = nullptr;
|
loop->tail = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +209,7 @@ void EventExecutor::_executor(ts::event::EventExecutor *loop) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sassert(event_handler->_event_ptr == linked_entry);
|
assert(event_handler->_event_ptr == linked_entry);
|
||||||
event_handler->_event_ptr = nullptr;
|
event_handler->_event_ptr = nullptr;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include <log/LogUtils.h>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <misc/base64.h>
|
#include <misc/base64.h>
|
||||||
#include "misc/endianness.h"
|
#include "misc/endianness.h"
|
||||||
@ -10,7 +9,6 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include "License.h"
|
#include "License.h"
|
||||||
|
|
||||||
using namespace ts;
|
|
||||||
using namespace license::teamspeak;
|
using namespace license::teamspeak;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
@ -263,7 +261,7 @@ void LicenseChain::print() {
|
|||||||
|
|
||||||
auto key = this->generatePublicKey();
|
auto key = this->generatePublicKey();
|
||||||
cout << "Public key: " << endl;
|
cout << "Public key: " << endl;
|
||||||
hexDump((char*) key.data(), (int) key.length(), (int) key.length(), (int) key.length(), [](string message) { cout << message << endl; });
|
//hexDump((char*) key.data(), (int) key.length(), (int) key.length(), (int) key.length(), [](string message) { cout << message << endl; });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LicenseChain::exportChain() {
|
std::string LicenseChain::exportChain() {
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "misc/memtracker.h"
|
#include "misc/memtracker.h"
|
||||||
#include "BasicChannel.h"
|
#include "BasicChannel.h"
|
||||||
#include "log/LogUtils.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ts;
|
using namespace ts;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
|
||||||
#include "bbcodes.h"
|
#include "bbcodes.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace bbcode::sloppy {
|
namespace bbcode::sloppy {
|
||||||
extern bool has_tag(std::string message, std::deque<std::string> tag);
|
extern bool has_tag(std::string message, std::deque<std::string> tag);
|
||||||
|
|
||||||
inline bool has_url(const std::string& message) { return has_tag(message, {"url"}); }
|
inline bool has_url(const std::string& message) { return has_tag(message, {"url"}); }
|
||||||
inline bool has_image(const std::string& message) { return has_tag(message, {"img"}); }
|
inline bool has_image(const std::string& message) { return has_tag(message, {"img"}); }
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
#include "TreeView.h"
|
#include "TreeView.h"
|
||||||
|
|
||||||
using namespace ts;
|
using namespace ts;
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "misc/advanced_mutex.h"
|
|
||||||
#include <Definitions.h>
|
#include <Definitions.h>
|
||||||
#include <deque>
|
#include "../misc/memtracker.h"
|
||||||
#include <ThreadPool/Mutex.h>
|
|
||||||
#include "misc/memtracker.h"
|
|
||||||
|
|
||||||
#ifndef __attribute_deprecated__
|
#ifndef __attribute_deprecated__
|
||||||
#define __attribute_deprecated__ [[deprecated]]
|
#define __attribute_deprecated__ [[deprecated]]
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
#include "LogSinks.h"
|
#include "LogSinks.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <spdlog/details/os.h>
|
|
||||||
#include <spdlog/formatter.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace spdlog;
|
using namespace spdlog;
|
||||||
@ -15,7 +13,7 @@ namespace logger {
|
|||||||
|
|
||||||
std::string_view message{formatted.data(), formatted.size()};
|
std::string_view message{formatted.data(), formatted.size()};
|
||||||
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
#ifdef HAVE_CXX_TERMINAL
|
||||||
if (terminal::active()) {
|
if (terminal::active()) {
|
||||||
//Split the string at new lines
|
//Split the string at new lines
|
||||||
size_t index{0}, found{0};
|
size_t index{0}, found{0};
|
||||||
|
@ -17,10 +17,6 @@
|
|||||||
#include <spdlog/async.h>
|
#include <spdlog/async.h>
|
||||||
#include <spdlog/sinks/rotating_file_sink.h>
|
#include <spdlog/sinks/rotating_file_sink.h>
|
||||||
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
|
||||||
#include <CXXTerminal/Terminal.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace spdlog;
|
using namespace spdlog;
|
||||||
@ -97,10 +93,12 @@ namespace logger {
|
|||||||
if(!::logger::currentConfig())
|
if(!::logger::currentConfig())
|
||||||
return default_logger();
|
return default_logger();
|
||||||
|
|
||||||
size_t group = 0;
|
size_t group{0};
|
||||||
if(::logger::currentConfig()->vs_group_size > 0 && serverId > 0)
|
if(::logger::currentConfig()->vs_group_size > 0 && serverId > 0) {
|
||||||
group = serverId / ::logger::currentConfig()->vs_group_size;
|
group = serverId / ::logger::currentConfig()->vs_group_size;
|
||||||
else group = -1;
|
} else {
|
||||||
|
group = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(loggers.count(group) == 0) {
|
if(loggers.count(group) == 0) {
|
||||||
lock_guard lock(loggerLock);
|
lock_guard lock(loggerLock);
|
||||||
@ -243,66 +241,4 @@ namespace logger {
|
|||||||
logConfig = nullptr;
|
logConfig = nullptr;
|
||||||
terminalSink = nullptr;
|
terminalSink = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexDump(void *addr, int len, int pad,int columnLength, void (*print)(string));
|
|
||||||
void hexDump(void *addr, int len, int pad,int columnLength) {
|
|
||||||
hexDump(addr, len, pad, columnLength, [](string str){ logMessage(0, "\n{}", str); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void hexDump(void *addr, int len, int pad,int columnLength, void (*print)(string)) {
|
|
||||||
int i;
|
|
||||||
uint8_t* buff = new uint8_t[pad+1];
|
|
||||||
unsigned char* pc = (unsigned char*)addr;
|
|
||||||
|
|
||||||
if (len <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stringstream line;
|
|
||||||
line << uppercase << hex << setfill('0');
|
|
||||||
// Process every byte in the data.
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
// Multiple of 16 means new line (with line offset).
|
|
||||||
|
|
||||||
if ((i % pad) == 0) {
|
|
||||||
// Just don't print ASCII for the zeroth line.
|
|
||||||
if (i != 0) {
|
|
||||||
line << buff;
|
|
||||||
print(line.str());
|
|
||||||
line = stringstream{};
|
|
||||||
line << hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Output the offset.
|
|
||||||
line << setw(4) << i << " ";
|
|
||||||
}
|
|
||||||
if(i % columnLength == 0 && i % pad != 0){
|
|
||||||
line << "| ";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now the hex code for the specific character.
|
|
||||||
line << setw(2) << (int) pc[i] << " ";
|
|
||||||
|
|
||||||
// And store a printable ASCII character for later.
|
|
||||||
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
|
|
||||||
buff[i % pad] = '.';
|
|
||||||
else
|
|
||||||
buff[i % pad] = pc[i];
|
|
||||||
buff[(i % pad) + 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pad out last line if not exactly 16 characters.
|
|
||||||
while ((i % pad) != 0) {
|
|
||||||
line << " ";
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
line << buff;
|
|
||||||
delete[] buff;
|
|
||||||
|
|
||||||
print(line.str());
|
|
||||||
line = stringstream{};
|
|
||||||
line << "Length: " << dec << len << " Addr: " << addr;
|
|
||||||
print(line.str());
|
|
||||||
}
|
|
@ -101,6 +101,4 @@ LOG_METHOD(logCritical);
|
|||||||
LOG_METHOD(logTrace);
|
LOG_METHOD(logTrace);
|
||||||
LOG_METHOD(debugMessage);
|
LOG_METHOD(debugMessage);
|
||||||
|
|
||||||
#undef LOG_METHOD
|
#undef LOG_METHOD
|
||||||
void hexDump(void* addr, int length, int numLength = 16, int columnLength = 8);
|
|
||||||
void hexDump(void* addr, int length, int numLength, int columnLength, void (*)(std::string));
|
|
@ -7,9 +7,12 @@
|
|||||||
#define sassert(exp) assert(exp)
|
#define sassert(exp) assert(exp)
|
||||||
#else
|
#else
|
||||||
#define S(s) #s
|
#define S(s) #s
|
||||||
#define sassert(exp) \
|
#define sassert(exp) \
|
||||||
do { \
|
do { \
|
||||||
if(!(exp)) \
|
if(!(exp)) { \
|
||||||
logCritical(0, "Soft assertion @{}:{} '{}' failed! This could cause fatal fails!", __FILE__, __LINE__, #exp); \
|
logCritical(0, \
|
||||||
|
"Soft assertion @{}:{} '{}' failed! This could cause fatal fails!", \
|
||||||
|
__FILE__, __LINE__, #exp); \
|
||||||
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif
|
#endif
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <protocol/Packet.h>
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include "./Packet.h"
|
||||||
|
|
||||||
#define DEBUG_ACKNOWLEDGE
|
#define DEBUG_ACKNOWLEDGE
|
||||||
namespace ts::connection {
|
namespace ts::connection {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Packet.h"
|
#include "./Packet.h"
|
||||||
|
|
||||||
namespace ts::compression {
|
namespace ts::compression {
|
||||||
/* Attention: These methods does not validate the data! */
|
/* Attention: These methods does not validate the data! */
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Packet.h"
|
|
||||||
#include <tomcrypt.h>
|
#include <tomcrypt.h>
|
||||||
|
#include "./Packet.h"
|
||||||
#undef byte /* the macro byte gets defined by tomcrypt_macros. We have to undefine it */
|
#undef byte /* the macro byte gets defined by tomcrypt_macros. We have to undefine it */
|
||||||
|
|
||||||
namespace ts::connection {
|
namespace ts::connection {
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include "./Packet.h"
|
#include "./Packet.h"
|
||||||
#include "../misc/endianness.h"
|
#include "../misc/endianness.h"
|
||||||
#include "../misc/spin_mutex.h"
|
#include "../misc/spin_mutex.h"
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <ThreadPool/Future.h>
|
|
||||||
#include <pipes/buffer.h>
|
#include <pipes/buffer.h>
|
||||||
#include "../query/Command.h"
|
#include "../query/Command.h"
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <list>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ThreadPool/Mutex.h>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "Packet.h"
|
|
||||||
#include "../misc/queue.h"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "./Packet.h"
|
||||||
|
#include "../misc/queue.h"
|
||||||
|
|
||||||
#ifndef NO_LOG
|
#ifndef NO_LOG
|
||||||
#include <log/LogUtils.h>
|
#include <log/LogUtils.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -194,27 +194,6 @@ namespace ts {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_JSON
|
|
||||||
Json::Value Command::buildJson() const {
|
|
||||||
Json::Value result;
|
|
||||||
result["command"] = this->_command;
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
for(auto it = this->bulks.begin(); it != this->bulks.end(); it++){
|
|
||||||
Json::Value& node = result["data"][index++];
|
|
||||||
for(const auto& elm : it->parms)
|
|
||||||
node[elm.key()] = elm.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
Json::Value& triggers = result["triggers"];
|
|
||||||
index = 0;
|
|
||||||
for(const auto& parm : this->paramethers)
|
|
||||||
triggers[index++] = parm;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::deque<std::string> Command::parms() { return this->paramethers; }
|
std::deque<std::string> Command::parms() { return this->paramethers; }
|
||||||
bool Command::hasParm(std::string parm) { return std::find(this->paramethers.begin(), this->paramethers.end(), parm) != this->paramethers.end(); }
|
bool Command::hasParm(std::string parm) { return std::find(this->paramethers.begin(), this->paramethers.end(), parm) != this->paramethers.end(); }
|
||||||
|
|
||||||
|
@ -17,10 +17,6 @@
|
|||||||
#include <pipes/buffer.h>
|
#include <pipes/buffer.h>
|
||||||
#include "../Variable.h"
|
#include "../Variable.h"
|
||||||
|
|
||||||
#ifdef HAVE_JSON
|
|
||||||
#include <json/json.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ts {
|
namespace ts {
|
||||||
#define PARM_TYPE(type, fromString, toString) \
|
#define PARM_TYPE(type, fromString, toString) \
|
||||||
BaseCommandParm(std::string key, type value) : BaseCommandParm(std::pair<std::string, std::string>(key, "")) {\
|
BaseCommandParm(std::string key, type value) : BaseCommandParm(std::pair<std::string, std::string>(key, "")) {\
|
||||||
@ -175,10 +171,6 @@ operator type(){ \
|
|||||||
|
|
||||||
[[nodiscard]] std::string build(bool escaped = true) const;
|
[[nodiscard]] std::string build(bool escaped = true) const;
|
||||||
|
|
||||||
#ifdef HAVE_JSON
|
|
||||||
Json::Value buildJson() const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const ParameterBulk& operator[](size_t index) const {
|
const ParameterBulk& operator[](size_t index) const {
|
||||||
if(bulks.size() <= index) throw std::invalid_argument("got out of length");
|
if(bulks.size() <= index) throw std::invalid_argument("got out of length");
|
||||||
return bulks[index];
|
return bulks[index];
|
||||||
|
@ -33,7 +33,6 @@ namespace sql {
|
|||||||
command copy = cmd;
|
command copy = cmd;
|
||||||
result res;
|
result res;
|
||||||
while((res = copy.execute()).code() == SQLITE_BUSY){
|
while((res = copy.execute()).code() == SQLITE_BUSY){
|
||||||
cerr << "Execute busy!" << endl;
|
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
fut.executionSucceed(res);
|
fut.executionSucceed(res);
|
||||||
|
@ -8,10 +8,11 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <ThreadPool/ThreadPool.h>
|
#include <ThreadPool/ThreadPool.h>
|
||||||
#include <ThreadPool/Future.h>
|
#include <ThreadPool/Future.h>
|
||||||
#include "../Variable.h"
|
|
||||||
#include <misc/memtracker.h>
|
#include <misc/memtracker.h>
|
||||||
#include <misc/lambda.h>
|
#include <misc/lambda.h>
|
||||||
|
|
||||||
|
#include "../Variable.h"
|
||||||
|
|
||||||
#define ALLOW_STACK_ALLOCATION
|
#define ALLOW_STACK_ALLOCATION
|
||||||
#define LOG_SQL_CMD [](const sql::result &res){ if(!res) logCritical(LOG_GENERAL, "Failed to execute sql command: " + std::to_string(res.code()) + "/" + res.msg() + " (" __FILE__ + ":" + to_string(__LINE__) + ")"); }
|
#define LOG_SQL_CMD [](const sql::result &res){ if(!res) logCritical(LOG_GENERAL, "Failed to execute sql command: " + std::to_string(res.code()) + "/" + res.msg() + " (" __FILE__ + ":" + to_string(__LINE__) + ")"); }
|
||||||
namespace sql {
|
namespace sql {
|
||||||
|
@ -393,8 +393,9 @@ std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &key_data, std
|
|||||||
|
|
||||||
if(!fs::exists(key_path)) {
|
if(!fs::exists(key_path)) {
|
||||||
try {
|
try {
|
||||||
if(key_path.has_parent_path())
|
if(key_path.has_parent_path()) {
|
||||||
fs::create_directories(key_path.parent_path());
|
fs::create_directories(key_path.parent_path());
|
||||||
|
}
|
||||||
} catch (fs::filesystem_error& error) {
|
} catch (fs::filesystem_error& error) {
|
||||||
logError(LOG_GENERAL, "Could not create key directory: " + string(error.what()));
|
logError(LOG_GENERAL, "Could not create key directory: " + string(error.what()));
|
||||||
}
|
}
|
||||||
@ -407,15 +408,19 @@ std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &key_data, std
|
|||||||
if(!key_bio) SSL_ERROR("Could not load key: ");
|
if(!key_bio) SSL_ERROR("Could not load key: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(readPublic)
|
if(readPublic) {
|
||||||
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PUBKEY(key_bio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
|
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PUBKEY(key_bio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
|
||||||
else
|
} else {
|
||||||
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(key_bio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
|
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(key_bio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
|
||||||
|
}
|
||||||
|
|
||||||
result->contains_private = !readPublic;
|
result->contains_private = !readPublic;
|
||||||
if(!key) {
|
if(!key) {
|
||||||
if(readPublic) {
|
if(readPublic) {
|
||||||
SSL_ERROR("Could not read key!");
|
SSL_ERROR("Could not read key!");
|
||||||
} else return this->loadSSL(key_data, error, rawData, true);
|
} else {
|
||||||
|
return this->loadSSL(key_data, error, rawData, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result->key = key;
|
result->key = key;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user