Merge branch '1.4.10'
# Conflicts: # CMakeLists.txt # src/Properties.h
This commit is contained in:
commit
4b48f2741c
@ -94,6 +94,7 @@ set(SOURCE_FILES
|
||||
src/misc/memtracker.cpp
|
||||
src/misc/digest.cpp
|
||||
src/misc/base64.cpp
|
||||
src/misc/net.cpp
|
||||
|
||||
src/lock/rw_mutex.cpp
|
||||
|
||||
@ -117,7 +118,7 @@ set(SOURCE_FILES
|
||||
src/protocol/Packet.cpp
|
||||
src/protocol/buffers.cpp
|
||||
src/protocol/buffers_allocator_c.cpp
|
||||
src/PermissionRegister.cpp
|
||||
src/PermissionManager.cpp
|
||||
src/Properties.cpp
|
||||
src/BasicChannel.cpp
|
||||
src/Error.cpp
|
||||
@ -128,12 +129,14 @@ set(SOURCE_FILES
|
||||
src/EventLoop.cpp
|
||||
|
||||
src/License.cpp
|
||||
src/PropertyDefinitions.cpp
|
||||
|
||||
src/bbcode/bbcodes.cpp
|
||||
|
||||
src/channel/TreeView.cpp
|
||||
src/protocol/ringbuffer.cpp
|
||||
src/protocol/AcknowledgeManager.cpp
|
||||
src/protocol/PacketLossCalculator.cpp
|
||||
)
|
||||
|
||||
set(HEADER_FILES
|
||||
@ -153,7 +156,7 @@ set(HEADER_FILES
|
||||
src/log/translation.h
|
||||
src/log/LogUtils.h
|
||||
|
||||
src/PermissionRegister.h
|
||||
src/PermissionManager.h
|
||||
src/protocol/buffers.h
|
||||
src/protocol/Packet.h
|
||||
src/Properties.h
|
||||
@ -196,11 +199,8 @@ if(HAVE_OPEN_SSL)
|
||||
openssl::crypto::static)
|
||||
endif()
|
||||
|
||||
find_package(mysql REQUIRED)
|
||||
|
||||
add_library(TeaSpeak STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
target_link_libraries(TeaSpeak PUBLIC
|
||||
mysql::client::static
|
||||
threadpool::static jsoncpp_lib
|
||||
${OPENSSL_LIBRARIES}
|
||||
tomcrypt::static
|
||||
@ -208,7 +208,18 @@ target_link_libraries(TeaSpeak PUBLIC
|
||||
dl
|
||||
)
|
||||
|
||||
target_compile_options(TeaSpeak PRIVATE "-Wall" "-DHAVE_MYSQL_H")
|
||||
find_package(mysql REQUIRED)
|
||||
set(mysql_FOUND ON)
|
||||
message("${mysql_FOUND}")
|
||||
if(mysql_FOUND)
|
||||
message("Found MySQL")
|
||||
target_link_libraries(TeaSpeak PUBLIC
|
||||
mysql::client::static
|
||||
)
|
||||
target_compile_options(TeaSpeak PRIVATE "-Wall" "-DHAVE_MYSQL_H")
|
||||
else()
|
||||
message("Building without MySQL Support")
|
||||
endif()
|
||||
|
||||
if (TEASPEAK_SERVER)
|
||||
target_link_libraries(TeaSpeak PUBLIC CXXTerminal::static)
|
||||
@ -268,14 +279,16 @@ if(BUILD_TESTS)
|
||||
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(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(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})
|
||||
@ -287,7 +300,7 @@ if(BUILD_TESTS)
|
||||
add_executable(CrashTest test/CrashTest.cpp ${SOURCE_FILES})
|
||||
target_link_libraries(CrashTest ${TEST_LIBRARIES})
|
||||
|
||||
add_executable(PorpertyTest test/PropertyTest.cpp ${SOURCE_FILES})
|
||||
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 src/misc/ip_router.cpp src/misc/ip_router.h)
|
||||
@ -299,12 +312,15 @@ if(BUILD_TESTS)
|
||||
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)
|
||||
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)
|
||||
|
||||
add_executable(IP-Router-Test test/ip_router.cpp src/misc/ip_router.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -145,7 +145,7 @@ const std::vector<ErrorType> ts::avariableErrors = {
|
||||
|
||||
{0x0F00, "token_invalid_id" , "invalid privilege key" },
|
||||
|
||||
{0x1001, "web_handshake_invalid" , "Invalid handshake" },
|
||||
{0x1000, "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" },
|
||||
|
@ -147,7 +147,7 @@ namespace ts {
|
||||
server_connect_banned = 0xd01,
|
||||
ban_flooding = 0xd03,
|
||||
token_invalid_id = 0xf00,
|
||||
web_handshake_invalid = 0x1001,
|
||||
web_handshake_invalid = 0x1000,
|
||||
web_handshake_unsupported = 0x1001,
|
||||
web_handshake_identity_unsupported = 0x1002,
|
||||
web_handshake_identity_proof_failed = 0x1003,
|
||||
|
@ -330,7 +330,8 @@ deque<std::shared_ptr<PermissionTypeEntry>> ts::permission::availablePermissions
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_delete_dbproperties, PermissionGroup::client_modify, "b_client_delete_dbproperties", "Delete a clients properties in the sql"),
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_create_modify_serverquery_login, PermissionGroup::client_modify, "b_client_create_modify_serverquery_login", "Create or modify own ServerQuery account"),
|
||||
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_query_create, PermissionGroup::client_modify, "b_client_query_create", "Create your own ServerQuery account"),
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_query_create, PermissionGroup::client_modify, "b_client_query_create", "Create a ServerQuery account for any user"),
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_query_create_own, PermissionGroup::client_modify, "b_client_query_create_own", "Create your own ServerQuery account"),
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_query_list, PermissionGroup::client_modify, "b_client_query_list", "List all ServerQuery accounts"),
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_query_list_own, PermissionGroup::client_modify, "b_client_query_list_own", "List all own ServerQuery accounts"),
|
||||
make_shared<PermissionTypeEntry>(PermissionType::b_client_query_rename, PermissionGroup::client_modify, "b_client_query_rename", "Rename a ServerQuery account"),
|
||||
@ -934,6 +935,7 @@ inline void init_mapping() {
|
||||
if(teamspeak::unmapping.empty()) teamspeak::unmapping = build_unmapping();
|
||||
}
|
||||
|
||||
/*
|
||||
template <typename T>
|
||||
inline deque<T> operator+(const deque<T>& a, const deque<T>& b) {
|
||||
deque<T> result;
|
||||
@ -941,6 +943,7 @@ inline deque<T> operator+(const deque<T>& a, const deque<T>& b) {
|
||||
result.insert(result.end(), b.begin(), b.end());
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
inline deque<string> mmget(teamspeak::MapType& map, teamspeak::GroupType type, const std::string& key) {
|
||||
return map[type].count(key) > 0 ? map[type].find(key)->second : deque<string>{};
|
||||
@ -952,16 +955,29 @@ inline std::deque<std::string> map_entry(std::string key, teamspeak::GroupType t
|
||||
if(key.find("_needed_modify_power_") == 1) {
|
||||
key = key.substr(strlen("x_needed_modify_power_"));
|
||||
|
||||
deque<string> result;
|
||||
if(map_table[type].count("i_" + key) > 0 || map_table[teamspeak::GroupType::GENERAL].count("i_" + key) > 0) result = mmget(map_table, type, "i_" + key) + mmget(map_table, teamspeak::GroupType::GENERAL, "i_" + key);
|
||||
else if(map_table[type].count("b_" + key) > 0 || map_table[teamspeak::GroupType::GENERAL].count("b_" + key) > 0) result = mmget(map_table, type, "b_" + key) + mmget(map_table, teamspeak::GroupType::GENERAL, "b_" + key);
|
||||
else result = {"x_" + key};
|
||||
|
||||
std::deque<std::string> result{};
|
||||
auto mapped_type = mmget(map_table, type, "i_" + key);
|
||||
result.insert(result.end(), mapped_type.begin(), mapped_type.end());
|
||||
if(type != teamspeak::GroupType::GENERAL) {
|
||||
auto mapped_general = mmget(map_table, teamspeak::GroupType::GENERAL, "i_" + key);
|
||||
result.insert(result.end(), mapped_general.begin(), mapped_general.end());
|
||||
}
|
||||
|
||||
for(auto& entry : result)
|
||||
entry = "i_needed_modify_power_" + entry.substr(2);
|
||||
return result;
|
||||
}
|
||||
if(map_table[type].count(key) > 0 || map_table[teamspeak::GroupType::GENERAL].count(key) > 0) return mmget(map_table, type, key) + mmget(map_table, teamspeak::GroupType::GENERAL, key);
|
||||
if(map_table[type].count(key) > 0 || map_table[teamspeak::GroupType::GENERAL].count(key) > 0) {
|
||||
std::deque<std::string> result{};
|
||||
auto mapped_type = mmget(map_table, type, key);
|
||||
result.insert(result.end(), mapped_type.begin(), mapped_type.end());
|
||||
if(type != teamspeak::GroupType::GENERAL) {
|
||||
auto mapped_general = mmget(map_table, teamspeak::GroupType::GENERAL, key);
|
||||
result.insert(result.end(), mapped_general.begin(), mapped_general.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return {key};
|
||||
}
|
||||
|
||||
|
@ -438,6 +438,7 @@ namespace ts {
|
||||
b_client_delete_dbproperties,
|
||||
b_client_create_modify_serverquery_login,
|
||||
b_client_query_create,
|
||||
b_client_query_create_own,
|
||||
b_client_query_list,
|
||||
b_client_query_list_own,
|
||||
b_client_query_rename,
|
||||
@ -812,11 +813,11 @@ namespace ts {
|
||||
};
|
||||
|
||||
struct PermissionFlaggedValue {
|
||||
PermissionValue value = permNotGranted;
|
||||
bool has_value = false;
|
||||
PermissionValue value{permNotGranted};
|
||||
bool has_value{false};
|
||||
|
||||
constexpr bool has_power() const { return this->has_value && (this->value > 0 || this->value == -1); }
|
||||
constexpr bool has_infinite_power() const { return this->has_value && this->value == -1; }
|
||||
[[nodiscard]] constexpr bool has_power() const { return this->has_value && (this->value > 0 || this->value == -1); }
|
||||
[[nodiscard]] constexpr bool has_infinite_power() const { return this->has_value && this->value == -1; }
|
||||
|
||||
inline bool operator==(const PermissionFlaggedValue& other) const { return other.value == this->value && other.has_value == this->has_value; }
|
||||
inline bool operator!=(const PermissionFlaggedValue& other) const { return !(*this == other); }
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include "log/LogUtils.h"
|
||||
#include "misc/memtracker.h"
|
||||
#include "Properties.h"
|
||||
@ -21,8 +22,6 @@ bool Properties::has(property::PropertyType type, int index) {
|
||||
if(!*it) continue;
|
||||
if(it->get()->type != type) continue;
|
||||
|
||||
index -= (int) it->get()->offset;
|
||||
if(index < 0) return false;
|
||||
return index < it->get()->length;
|
||||
}
|
||||
return false;
|
||||
@ -34,10 +33,6 @@ PropertyWrapper Properties::find(property::PropertyType type, int index) {
|
||||
if(bulk->type != type)
|
||||
continue;
|
||||
|
||||
index -= (int) bulk->offset;
|
||||
if(index < 0)
|
||||
break;
|
||||
|
||||
if(index >= bulk->length)
|
||||
break;
|
||||
|
||||
@ -72,7 +67,7 @@ std::vector<PropertyWrapper> Properties::all_properties() {
|
||||
return result;
|
||||
}
|
||||
|
||||
PropertyWrapper::PropertyWrapper(ts::Properties* handle, ts::PropertyData *data, const std::shared_ptr<ts::PropertyBundle> &bundle_lock) : handle(handle), data_ptr(data), bundle_lock(bundle_lock) {
|
||||
PropertyWrapper::PropertyWrapper(ts::Properties* handle, ts::PropertyData *data, std::shared_ptr<ts::PropertyBundle> bundle_lock) : handle{handle}, data_ptr{data}, bundle_lock{std::move(bundle_lock)} {
|
||||
}
|
||||
|
||||
void PropertyWrapper::trigger_update() {
|
||||
@ -84,7 +79,7 @@ void PropertyWrapper::trigger_update() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Properties::register_property_type(ts::property::PropertyType type, size_t length, size_t offset) {
|
||||
bool Properties::register_property_type(ts::property::PropertyType type, size_t length) {
|
||||
for(auto& bulk : this->properties)
|
||||
if(bulk->type == type)
|
||||
return false;
|
||||
@ -95,7 +90,6 @@ bool Properties::register_property_type(ts::property::PropertyType type, size_t
|
||||
|
||||
for(int index = 0; index < bundle->length; index++) {
|
||||
auto& property = bundle->properties[index];
|
||||
property.description.~shared_ptr<property::PropertyDescription>();
|
||||
property.value.~string();
|
||||
property.value_lock.~spin_lock();
|
||||
property.casted_value.~any();
|
||||
@ -104,7 +98,6 @@ bool Properties::register_property_type(ts::property::PropertyType type, size_t
|
||||
});
|
||||
|
||||
ptr->type = type;
|
||||
ptr->offset = offset;
|
||||
ptr->length = length;
|
||||
|
||||
for(int index = 0; index < length; index++) {
|
||||
@ -113,7 +106,7 @@ bool Properties::register_property_type(ts::property::PropertyType type, size_t
|
||||
new (&property.casted_value) any();
|
||||
new (&property.value_lock) spin_lock();
|
||||
new (&property.value) string();
|
||||
new (&property.description) shared_ptr<property::PropertyDescription>(property::impl::info(type, (int) (offset + index)));
|
||||
property.description = &property::describe(type, index);
|
||||
property.flag_modified = false;
|
||||
property.flag_db_reference = false;
|
||||
|
||||
@ -127,470 +120,7 @@ bool Properties::register_property_type(ts::property::PropertyType type, size_t
|
||||
|
||||
namespace ts {
|
||||
namespace property {
|
||||
PropertyDescription::PropertyDescription(int property_id, PropertyType property_type, const std::string &name, const std::string &default_value, property::ValueType type, property::flag_type flags) noexcept : name(name), default_value(default_value),
|
||||
type_value(type), flags(flags), property_index(property_id),
|
||||
type_property(property_type) {
|
||||
std::transform(this->name.begin(), this->name.end(), this->name.begin(), ::tolower);
|
||||
}
|
||||
|
||||
#define FLAG_SS (FLAG_SNAPSHOT | FLAG_SAVE)
|
||||
#define FLAG_SERVER_VV (FLAG_SERVER_VARIABLE | FLAG_SERVER_VIEW)
|
||||
#define FLAG_SERVER_VVSS (FLAG_SERVER_VV | FLAG_SS)
|
||||
|
||||
#define FLAG_CLIENT_VV (FLAG_CLIENT_VARIABLE | FLAG_CLIENT_VIEW)
|
||||
#define FLAG_CLIENT_VVSS (FLAG_CLIENT_VV | FLAG_SS)
|
||||
|
||||
array<shared_ptr<PropertyDescription>, VirtualServerProperties::VIRTUALSERVER_ENDMARKER> virtualserver_info = {
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_UNDEFINED, "VIRTUALSERVER_UNDEFINED", "", TYPE_UNKNOWN, 0), //Must be at index 0!
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_ID, "VIRTUALSERVER_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VIEW), //available when connected
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_UNIQUE_IDENTIFIER, "VIRTUALSERVER_UNIQUE_IDENTIFIER", "", TYPE_STRING, FLAG_SERVER_VV | FLAG_SNAPSHOT),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_NAME, "VIRTUALSERVER_NAME", "Another TeaSpeak server software user", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_WELCOMEMESSAGE, "VIRTUALSERVER_WELCOMEMESSAGE", "Welcome on another TeaSpeak server. (Download now and a license fee is not your cup of tea! [URL]www.teaspeak.de[/URL])", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_PLATFORM, "VIRTUALSERVER_PLATFORM", "undefined", TYPE_STRING, FLAG_SERVER_VIEW),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_VERSION, "VIRTUALSERVER_VERSION", "undefined", TYPE_STRING, FLAG_SERVER_VIEW),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MAXCLIENTS, "VIRTUALSERVER_MAXCLIENTS", "120", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_PASSWORD, "VIRTUALSERVER_PASSWORD", "", TYPE_STRING, FLAG_SS | FLAG_USER_EDITABLE),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_CLIENTS_ONLINE, "virtualserver_clientsonline", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_CHANNELS_ONLINE, "virtualserver_channelsonline", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables),
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_QUERYCLIENTS_ONLINE, "virtualserver_queryclientsonline", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_CREATED, "VIRTUALSERVER_CREATED", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VIEW | FLAG_SS), //available when connected, stores the time when the server was created
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_UPTIME, "VIRTUALSERVER_UPTIME", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables), the time since the server was started
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_CODEC_ENCRYPTION_MODE, "VIRTUALSERVER_CODEC_ENCRYPTION_MODE", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available and always up-to-date when connected
|
||||
|
||||
// Rare properties
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_KEYPAIR, "VIRTUALSERVER_KEYPAIR", "", TYPE_STRING, FLAG_SS), //internal use
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTMESSAGE, "VIRTUALSERVER_HOSTMESSAGE", "Welcome", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, not updated while connected
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTMESSAGE_MODE, "VIRTUALSERVER_HOSTMESSAGE_MODE", "1", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, not updated while connected
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_SERVER_GROUP, "VIRTUALSERVER_DEFAULT_SERVER_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //the manager permissions server group that a new manager gets assigned
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_MUSIC_GROUP, "VIRTUALSERVER_DEFAULT_MUSIC_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //the manager permissions server group that a new manager gets assigned
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_CHANNEL_GROUP, "VIRTUALSERVER_DEFAULT_CHANNEL_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //the channel permissions group that a new manager gets assigned when joining a channel
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_FLAG_PASSWORD, "VIRTUALSERVER_FLAG_PASSWORD", "0", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP, "VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SERVER_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //the channel permissions group that a manager gets assigned when creating a channel
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH, "VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH, "VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBANNER_URL, "VIRTUALSERVER_HOSTBANNER_URL", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBANNER_GFX_URL, "VIRTUALSERVER_HOSTBANNER_GFX_URL", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBANNER_GFX_INTERVAL, "VIRTUALSERVER_HOSTBANNER_GFX_INTERVAL", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_COMPLAIN_AUTOBAN_COUNT, "VIRTUALSERVER_COMPLAIN_AUTOBAN_COUNT", "5", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_COMPLAIN_AUTOBAN_TIME, "VIRTUALSERVER_COMPLAIN_AUTOBAN_TIME", "5", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_COMPLAIN_REMOVE_TIME, "VIRTUALSERVER_COMPLAIN_REMOVE_TIME", "5", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MIN_CLIENTS_IN_CHANNEL_BEFORE_FORCED_SILENCE, "VIRTUALSERVER_MIN_CLIENTS_IN_CHANNEL_BEFORE_FORCED_SILENCE", "20", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE),//only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_PRIORITY_SPEAKER_DIMM_MODIFICATOR, "VIRTUALSERVER_PRIORITY_SPEAKER_DIMM_MODIFICATOR", "-18", TYPE_FLOAT, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_ANTIFLOOD_POINTS_TICK_REDUCE, "VIRTUALSERVER_ANTIFLOOD_POINTS_TICK_REDUCE", "25", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK, "VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK", "150", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_IP_BLOCK, "VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_IP_BLOCK", "300", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_CLIENT_CONNECTIONS, "VIRTUALSERVER_CLIENT_CONNECTIONS", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_QUERY_CLIENT_CONNECTIONS, "VIRTUALSERVER_QUERY_CLIENT_CONNECTIONS", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBUTTON_TOOLTIP, "VIRTUALSERVER_HOSTBUTTON_TOOLTIP", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBUTTON_URL, "VIRTUALSERVER_HOSTBUTTON_URL", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBUTTON_GFX_URL, "VIRTUALSERVER_HOSTBUTTON_GFX_URL", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOSTBANNER_MODE, "VIRTUALSERVER_HOSTBANNER_MODE", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_FILEBASE, "VIRTUALSERVER_FILEBASE", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //not available to clients, stores the folder used for file transfers
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DOWNLOAD_QUOTA, "VIRTUALSERVER_DOWNLOAD_QUOTA", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_UPLOAD_QUOTA, "VIRTUALSERVER_UPLOAD_QUOTA", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MONTH_BYTES_DOWNLOADED, "VIRTUALSERVER_MONTH_BYTES_DOWNLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MONTH_BYTES_UPLOADED, "VIRTUALSERVER_MONTH_BYTES_UPLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_BYTES_DOWNLOADED, "VIRTUALSERVER_TOTAL_BYTES_DOWNLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_BYTES_UPLOADED, "VIRTUALSERVER_TOTAL_BYTES_UPLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_PORT, "VIRTUALSERVER_PORT", "9987", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_HOST, "VIRTUALSERVER_HOST", "0.0.0.0,::", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //internal use | contains comma separated ip list
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_AUTOSTART, "VIRTUALSERVER_AUTOSTART", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MACHINE_ID, "VIRTUALSERVER_MACHINE_ID", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL, "VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL", "8", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LOG_CLIENT, "VIRTUALSERVER_LOG_CLIENT", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LOG_QUERY, "VIRTUALSERVER_LOG_QUERY", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LOG_CHANNEL, "VIRTUALSERVER_LOG_CHANNEL", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LOG_PERMISSIONS, "VIRTUALSERVER_LOG_PERMISSIONS", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LOG_SERVER, "VIRTUALSERVER_LOG_SERVER", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LOG_FILETRANSFER, "VIRTUALSERVER_LOG_FILETRANSFER", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_NAME_PHONETIC, "VIRTUALSERVER_NAME_PHONETIC", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_ICON_ID, "VIRTUALSERVER_ICON_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_RESERVED_SLOTS, "VIRTUALSERVER_RESERVED_SLOTS", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_PACKETLOSS_SPEECH, "VIRTUALSERVER_TOTAL_PACKETLOSS_SPEECH", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_PACKETLOSS_KEEPALIVE, "VIRTUALSERVER_TOTAL_PACKETLOSS_KEEPALIVE", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_PACKETLOSS_CONTROL, "VIRTUALSERVER_TOTAL_PACKETLOSS_CONTROL", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_PACKETLOSS_TOTAL, "VIRTUALSERVER_TOTAL_PACKETLOSS_TOTAL", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_TOTAL_PING, "VIRTUALSERVER_TOTAL_PING", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_WEBLIST_ENABLED, "VIRTUALSERVER_WEBLIST_ENABLED", "1", TYPE_BOOL, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY, "VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY", "", TYPE_STRING, FLAG_SAVE), //internal use
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY, "VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY", "1", TYPE_BOOL, FLAG_SERVER_VV | FLAG_SAVE | FLAG_USER_EDITABLE), //available when connected
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT, "VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT", "60", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE), //available when connected, always up-to-date
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MIN_CLIENT_VERSION, "VIRTUALSERVER_MIN_CLIENT_VERSION", "1445512488", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MIN_ANDROID_VERSION, "VIRTUALSERVER_MIN_ANDROID_VERSION", "1407159763", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MIN_IOS_VERSION, "VIRTUALSERVER_MIN_IOS_VERSION", "1407159763", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MIN_WINPHONE_VERSION, "VIRTUALSERVER_MIN_WINPHONE_VERSION", "1407159763", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MAX_CHANNELS, "VIRTUALSERVER_MAX_CHANNELS", "1000", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LAST_CLIENT_CONNECT, "VIRTUALSERVER_LAST_CLIENT_CONNECT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LAST_QUERY_CONNECT, "VIRTUALSERVER_LAST_QUERY_CONNECT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LAST_CLIENT_DISCONNECT, "VIRTUALSERVER_LAST_CLIENT_DISCONNECT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_LAST_QUERY_DISCONNECT, "VIRTUALSERVER_LAST_QUERY_DISCONNECT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS), //only available on request (=> requestServerVariables)
|
||||
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_WEB_PORT, "VIRTUALSERVER_WEB_PORT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_WEB_HOST, "VIRTUALSERVER_WEB_HOST", "0.0.0.0", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_CLIENT_DESCRIPTION, "VIRTUALSERVER_DEFAULT_CLIENT_DESCRIPTION", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_CHANNEL_DESCRIPTION, "VIRTUALSERVER_DEFAULT_CHANNEL_DESCRIPTION", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DEFAULT_CHANNEL_TOPIC, "VIRTUALSERVER_DEFAULT_CHANNEL_TOPIC", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_MUSIC_BOT_LIMIT, "VIRTUALSERVER_MUSIC_BOT_LIMIT", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_SPOKEN_TIME, "VIRTUALSERVER_SPOKEN_TIME", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_NEW | FLAG_SAVE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_DISABLE_IP_SAVING, "VIRTUALSERVER_DISABLE_IP_SAVING", "0", TYPE_BOOL, FLAG_INTERNAL | FLAG_NEW | FLAG_SAVE | FLAG_USER_EDITABLE), //only available on request (=> requestServerVariables)
|
||||
make_shared<PropertyDescription>(VIRTUALSERVER_COUNTRY_CODE, "VIRTUALSERVER_COUNTRY_CODE", "XX", TYPE_STRING, FLAG_SERVER_VV | FLAG_SAVE | FLAG_USER_EDITABLE) //available when connected
|
||||
};
|
||||
|
||||
array<shared_ptr<PropertyDescription>, ChannelProperties::CHANNEL_ENDMARKER> channel_info = {
|
||||
make_shared<PropertyDescription>(CHANNEL_UNDEFINED, "CHANNEL_UNDEFINED", "", TYPE_UNKNOWN, 0), //Must be at index 0!
|
||||
make_shared<PropertyDescription>(CHANNEL_ID, "cid", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS),
|
||||
make_shared<PropertyDescription>(CHANNEL_PID, "cpid", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS),
|
||||
make_shared<PropertyDescription>(CHANNEL_NAME, "CHANNEL_NAME", "undefined", TYPE_STRING, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_TOPIC, "CHANNEL_TOPIC", "", TYPE_STRING, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_DESCRIPTION, "CHANNEL_DESCRIPTION", "", TYPE_STRING, FLAG_CHANNEL_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE), //Must be requested (=> requestChannelDescription)
|
||||
make_shared<PropertyDescription>(CHANNEL_PASSWORD, "CHANNEL_PASSWORD", "0", TYPE_STRING, FLAG_SS | FLAG_USER_EDITABLE), //not available manager side
|
||||
make_shared<PropertyDescription>(CHANNEL_CODEC, "CHANNEL_CODEC", "4", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_CODEC_QUALITY, "CHANNEL_CODEC_QUALITY", "7", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_MAXCLIENTS, "CHANNEL_MAXCLIENTS", "-1", TYPE_SIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_MAXFAMILYCLIENTS, "CHANNEL_MAXFAMILYCLIENTS", "-1", TYPE_SIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_ORDER, "CHANNEL_ORDER", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_PERMANENT, "CHANNEL_FLAG_PERMANENT", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_SEMI_PERMANENT, "CHANNEL_FLAG_SEMI_PERMANENT", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_DEFAULT, "CHANNEL_FLAG_DEFAULT", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_PASSWORD, "CHANNEL_FLAG_PASSWORD", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_CODEC_LATENCY_FACTOR, "CHANNEL_CODEC_LATENCY_FACTOR", "1", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_CODEC_IS_UNENCRYPTED, "CHANNEL_CODEC_IS_UNENCRYPTED", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_SECURITY_SALT, "CHANNEL_SECURITY_SALT", "", TYPE_STRING, FLAG_SS), //Not available manager side, not used in teamspeak, only SDK. Sets the options+salt for security hash.
|
||||
make_shared<PropertyDescription>(CHANNEL_DELETE_DELAY, "CHANNEL_DELETE_DELAY", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //How many seconds to wait before deleting this channel
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_MAXCLIENTS_UNLIMITED, "CHANNEL_FLAG_MAXCLIENTS_UNLIMITED", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED, "CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE),//Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED, "CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE),//Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_ARE_SUBSCRIBED, "CHANNEL_FLAG_ARE_SUBSCRIBED", "1", TYPE_BOOL, FLAG_INTERNAL), //Only available manager side, stores whether we are subscribed to this channel
|
||||
make_shared<PropertyDescription>(CHANNEL_FILEPATH, "CHANNEL_FILEPATH", "", TYPE_STRING, FLAG_SS), //not available manager side, the folder used for file-transfers for this channel
|
||||
make_shared<PropertyDescription>(CHANNEL_NEEDED_TALK_POWER, "CHANNEL_NEEDED_TALK_POWER", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FORCED_SILENCE, "CHANNEL_FORCED_SILENCE", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_NAME_PHONETIC, "CHANNEL_NAME_PHONETIC", "", TYPE_STRING, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_ICON_ID, "CHANNEL_ICON_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_PRIVATE, "CHANNEL_FLAG_PRIVATE", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_LAST_LEFT, "CHANNEL_LAST_LEFT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SAVE | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_CREATED_AT, "CHANNEL_CREATED_AT", "0", TYPE_UNSIGNED_NUMBER, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_CREATED_BY, "CHANNEL_CREATED_BY", "0", TYPE_UNSIGNED_NUMBER, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW), //Available for all channels that are "in view", always up-to-date
|
||||
make_shared<PropertyDescription>(CHANNEL_CONVERSATION_HISTORY_LENGTH, "CHANNEL_CONVERSATION_HISTORY_LENGTH", "1500", TYPE_SIGNED_NUMBER, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW | FLAG_USER_EDITABLE),
|
||||
make_shared<PropertyDescription>(CHANNEL_FLAG_CONVERSATION_PRIVATE, "CHANNEL_FLAG_CONVERSATION_PRIVATE", "0", TYPE_BOOL, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW | FLAG_USER_EDITABLE)
|
||||
};
|
||||
|
||||
array<shared_ptr<PropertyDescription>, GroupProperties::GROUP_ENDMARKER> group_info = {
|
||||
make_shared<PropertyDescription>(GROUP_UNDEFINED, "GROUP_UNDEFINED", "", TYPE_UNKNOWN, 0),
|
||||
make_shared<PropertyDescription>(GROUP_ID, "gid", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL),
|
||||
make_shared<PropertyDescription>(GROUP_TYPE, "type", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW),
|
||||
make_shared<PropertyDescription>(GROUP_NAME, "name", "Undefined group", TYPE_STRING, FLAG_GROUP_VIEW),
|
||||
make_shared<PropertyDescription>(GROUP_SORTID, "sortid", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW),
|
||||
make_shared<PropertyDescription>(GROUP_SAVEDB, "savedb", "0", TYPE_BOOL, FLAG_GROUP_VIEW),
|
||||
make_shared<PropertyDescription>(GROUP_NAMEMODE, "namemode", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW),
|
||||
make_shared<PropertyDescription>(GROUP_ICONID, "iconid", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW)
|
||||
};
|
||||
|
||||
array<shared_ptr<PropertyDescription>, ClientProperties::CLIENT_ENDMARKER> client_info = {
|
||||
make_shared<PropertyDescription>(CLIENT_UNDEFINED, "CLIENT_UNDEFINED", "undefined", TYPE_UNKNOWN, 0),
|
||||
make_shared<PropertyDescription>(CLIENT_UNIQUE_IDENTIFIER, "CLIENT_UNIQUE_IDENTIFIER", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SNAPSHOT | FLAG_GLOBAL), //automatically up-to-date for any manager "in view", can be used to identify this particular manager installation
|
||||
make_shared<PropertyDescription>(CLIENT_NICKNAME, "CLIENT_NICKNAME", "undefined", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SAVE_MUSIC | FLAG_SNAPSHOT | FLAG_GLOBAL | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_VERSION, "CLIENT_VERSION", "unknown", TYPE_STRING, FLAG_CLIENT_VVSS | FLAG_USER_EDITABLE | FLAG_GLOBAL | FLAG_SAVE_MUSIC), //for other clients than ourself, this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_PLATFORM, "CLIENT_PLATFORM", "unknown", TYPE_STRING, FLAG_CLIENT_VVSS | FLAG_USER_EDITABLE | FLAG_GLOBAL | FLAG_SAVE_MUSIC), //for other clients than ourself, this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_FLAG_TALKING, "CLIENT_FLAG_TALKING", "0", TYPE_BOOL, FLAG_INTERNAL), //automatically up-to-date for any manager that can be heard (in room / whisper)
|
||||
make_shared<PropertyDescription>(CLIENT_INPUT_MUTED, "CLIENT_INPUT_MUTED", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients microphone mute status
|
||||
make_shared<PropertyDescription>(CLIENT_OUTPUT_MUTED, "CLIENT_OUTPUT_MUTED", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients headphones/speakers/mic combined mute status
|
||||
make_shared<PropertyDescription>(CLIENT_OUTPUTONLY_MUTED, "CLIENT_OUTPUTONLY_MUTED", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients headphones/speakers only mute status
|
||||
make_shared<PropertyDescription>(CLIENT_INPUT_HARDWARE, "CLIENT_INPUT_HARDWARE", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients microphone hardware status (is the capture device opened?)
|
||||
make_shared<PropertyDescription>(CLIENT_OUTPUT_HARDWARE, "CLIENT_OUTPUT_HARDWARE", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients headphone/speakers hardware status (is the playback device opened?)
|
||||
make_shared<PropertyDescription>(CLIENT_DEFAULT_CHANNEL, "CLIENT_DEFAULT_CHANNEL", "", TYPE_STRING, FLAG_INTERNAL), //only usable for ourself, the default channel we used to connect on our last connection attempt
|
||||
make_shared<PropertyDescription>(CLIENT_DEFAULT_CHANNEL_PASSWORD, "CLIENT_DEFAULT_CHANNEL_PASSWORD", "", TYPE_STRING, FLAG_INTERNAL), //internal use
|
||||
make_shared<PropertyDescription>(CLIENT_SERVER_PASSWORD, "CLIENT_SERVER_PASSWORD", "", TYPE_STRING, FLAG_INTERNAL), //internal use
|
||||
make_shared<PropertyDescription>(CLIENT_META_DATA, "CLIENT_META_DATA", "", TYPE_STRING, FLAG_CLIENT_VIEW| FLAG_GLOBAL|FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", not used by TeamSpeak, free storage for sdk users
|
||||
make_shared<PropertyDescription>(CLIENT_IS_RECORDING, "CLIENT_IS_RECORDING", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_VERSION_SIGN, "CLIENT_VERSION_SIGN", "", TYPE_STRING, FLAG_INTERNAL), //sign
|
||||
make_shared<PropertyDescription>(CLIENT_SECURITY_HASH, "CLIENT_SECURITY_HASH", "", TYPE_STRING, FLAG_INTERNAL), //SDK use, not used by teamspeak. Hash is provided by an outside source. A channel will use the security salt + other manager data to calculate a hash, which must be the same as the one provided here.
|
||||
|
||||
//Rare properties
|
||||
make_shared<PropertyDescription>(CLIENT_KEY_OFFSET, "CLIENT_KEY_OFFSET", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL), //internal use
|
||||
make_shared<PropertyDescription>(CLIENT_LOGIN_NAME, "CLIENT_LOGIN_NAME", "", TYPE_STRING, FLAG_CLIENT_VARIABLE| FLAG_GLOBAL), //used for serverquery clients, makes no sense on normal clients currently
|
||||
make_shared<PropertyDescription>(CLIENT_LOGIN_PASSWORD, "CLIENT_LOGIN_PASSWORD", "", TYPE_STRING, FLAG_INTERNAL| FLAG_GLOBAL), //used for serverquery clients, makes no sense on normal clients currently
|
||||
make_shared<PropertyDescription>(CLIENT_DATABASE_ID, "CLIENT_DATABASE_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_GLOBAL), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds database manager id
|
||||
make_shared<PropertyDescription>(CLIENT_ID, "clid", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VV), //clid!
|
||||
make_shared<PropertyDescription>(CLIENT_HARDWARE_ID, "hwid", "", TYPE_STRING, FLAG_SAVE), //hwid!
|
||||
make_shared<PropertyDescription>(CLIENT_CHANNEL_GROUP_ID, "CLIENT_CHANNEL_GROUP_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds database manager id
|
||||
make_shared<PropertyDescription>(CLIENT_SERVERGROUPS, "CLIENT_SERVERGROUPS", "0", TYPE_STRING, FLAG_CLIENT_VIEW), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds all servergroups manager belongs too
|
||||
make_shared<PropertyDescription>(CLIENT_CREATED, "CLIENT_CREATED", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE_MUSIC | FLAG_SNAPSHOT | FLAG_GLOBAL), //this needs to be requested (=> requestClientVariables), first time this manager connected to this server
|
||||
make_shared<PropertyDescription>(CLIENT_LASTCONNECTED, "CLIENT_LASTCONNECTED", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SNAPSHOT | FLAG_GLOBAL), //this needs to be requested (=> requestClientVariables), last time this manager connected to this server
|
||||
make_shared<PropertyDescription>(CLIENT_TOTALCONNECTIONS, "CLIENT_TOTALCONNECTIONS", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_CLIENT_VIEW | FLAG_SNAPSHOT | FLAG_GLOBAL), //this needs to be requested (=> requestClientVariables), how many times this manager connected to this server
|
||||
make_shared<PropertyDescription>(CLIENT_AWAY, "CLIENT_AWAY", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients away status
|
||||
make_shared<PropertyDescription>(CLIENT_AWAY_MESSAGE, "CLIENT_AWAY_MESSAGE", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this clients away message
|
||||
make_shared<PropertyDescription>(CLIENT_TYPE, "CLIENT_TYPE", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_GLOBAL), //automatically up-to-date for any manager "in view", determines if this is a real manager or a server-query connection
|
||||
make_shared<PropertyDescription>(CLIENT_TYPE_EXACT, "CLIENT_TYPE_EXACT", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_NEW | FLAG_GLOBAL), //automatically up-to-date for any manager "in view", determines if this is a real manager or a server-query connection
|
||||
make_shared<PropertyDescription>(CLIENT_FLAG_AVATAR, "CLIENT_FLAG_AVATAR", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SAVE | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", this manager got an avatar
|
||||
make_shared<PropertyDescription>(CLIENT_TALK_POWER, "CLIENT_TALK_POWER", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds database manager id
|
||||
make_shared<PropertyDescription>(CLIENT_TALK_REQUEST, "CLIENT_TALK_REQUEST", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds timestamp where manager requested to talk
|
||||
make_shared<PropertyDescription>(CLIENT_TALK_REQUEST_MSG, "CLIENT_TALK_REQUEST_MSG", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds matter for the request
|
||||
make_shared<PropertyDescription>(CLIENT_DESCRIPTION, "CLIENT_DESCRIPTION", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_IS_TALKER, "CLIENT_IS_TALKER", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_MONTH_BYTES_UPLOADED, "CLIENT_MONTH_BYTES_UPLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE), //this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_MONTH_BYTES_DOWNLOADED, "CLIENT_MONTH_BYTES_DOWNLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE), //this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_TOTAL_BYTES_UPLOADED, "CLIENT_TOTAL_BYTES_UPLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE), //this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_TOTAL_BYTES_DOWNLOADED, "CLIENT_TOTAL_BYTES_DOWNLOADED", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE), //this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_TOTAL_ONLINE_TIME, "CLIENT_TOTAL_ONLINE_TIME", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE | FLAG_NEW), //this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_MONTH_ONLINE_TIME, "CLIENT_MONTH_ONLINE_TIME", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE | FLAG_NEW), //this needs to be requested (=> requestClientVariables)
|
||||
make_shared<PropertyDescription>(CLIENT_IS_PRIORITY_SPEAKER, "CLIENT_IS_PRIORITY_SPEAKER", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_UNREAD_MESSAGES, "CLIENT_UNREAD_MESSAGES", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_NICKNAME_PHONETIC, "CLIENT_NICKNAME_PHONETIC", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_NEEDED_SERVERQUERY_VIEW_POWER, "CLIENT_NEEDED_SERVERQUERY_VIEW_POWER", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_DEFAULT_TOKEN, "CLIENT_DEFAULT_TOKEN", "", TYPE_STRING, FLAG_INTERNAL), //only usable for ourself, the default token we used to connect on our last connection attempt
|
||||
make_shared<PropertyDescription>(CLIENT_ICON_ID, "CLIENT_ICON_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_CLIENT_VARIABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_IS_CHANNEL_COMMANDER, "CLIENT_IS_CHANNEL_COMMANDER", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE | FLAG_SAVE_MUSIC), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_COUNTRY, "CLIENT_COUNTRY", "TS", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_CLIENT_VARIABLE | FLAG_GLOBAL | FLAG_SAVE_MUSIC | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view"
|
||||
make_shared<PropertyDescription>(CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID, "CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW), //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, contains channel_id where the channel_group_id is set from
|
||||
make_shared<PropertyDescription>(CLIENT_BADGES, "CLIENT_BADGES", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", stores icons for partner badges
|
||||
make_shared<PropertyDescription>(CLIENT_MYTEAMSPEAK_ID, "CLIENT_MYTEAMSPEAK_ID", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SS | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", stores icons for partner badges
|
||||
make_shared<PropertyDescription>(CLIENT_INTEGRATIONS, "CLIENT_INTEGRATIONS", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE), //automatically up-to-date for any manager "in view", stores icons for partner badges
|
||||
make_shared<PropertyDescription>(CLIENT_ACTIVE_INTEGRATIONS_INFO, "CLIENT_ACTIVE_INTEGRATIONS_INFO", "", TYPE_STRING, FLAG_INTERNAL | FLAG_USER_EDITABLE),
|
||||
|
||||
//Using FLAG_GLOBAL here,lse they will be overridden on clientinit
|
||||
make_shared<PropertyDescription>(CLIENT_TEAFORO_ID, "CLIENT_TEAFORO_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_GLOBAL),
|
||||
make_shared<PropertyDescription>(CLIENT_TEAFORO_NAME, "CLIENT_TEAFORO_NAME", "", TYPE_STRING, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_GLOBAL),
|
||||
make_shared<PropertyDescription>(CLIENT_TEAFORO_FLAGS, "CLIENT_TEAFORO_FLAGS", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_GLOBAL),
|
||||
|
||||
//Music bot stuff
|
||||
make_shared<PropertyDescription>(CLIENT_OWNER, "CLIENT_OWNER", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW),
|
||||
make_shared<PropertyDescription>(CLIENT_BOT_TYPE, "CLIENT_BOT_TYPE", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_SAVE_MUSIC | FLAG_USER_EDITABLE | FLAG_CLIENT_VIEW),
|
||||
make_shared<PropertyDescription>(CLIENT_LAST_CHANNEL, "CLIENT_LAST_CHANNEL", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_INTERNAL | FLAG_SAVE_MUSIC),
|
||||
make_shared<PropertyDescription>(CLIENT_PLAYER_STATE, "PLAYER_STATE", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_SAVE_MUSIC),
|
||||
make_shared<PropertyDescription>(CLIENT_PLAYER_VOLUME, "PLAYER_VOLUME", "1", TYPE_FLOAT, FLAG_NEW | FLAG_SAVE_MUSIC | FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE),
|
||||
make_shared<PropertyDescription>(CLIENT_PLAYLIST_ID, "CLIENT_PLAYLIST_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VARIABLE | FLAG_SAVE_MUSIC),
|
||||
make_shared<PropertyDescription>(CLIENT_DISABLED, "CLIENT_DISABLED", "0", TYPE_BOOL, FLAG_NEW | FLAG_CLIENT_VARIABLE),
|
||||
make_shared<PropertyDescription>(CLIENT_UPTIME_MODE, "CLIENT_UPTIME_MODE", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE_MUSIC),
|
||||
make_shared<PropertyDescription>(CLIENT_FLAG_NOTIFY_SONG_CHANGE, "CLIENT_FLAG_NOTIFY_SONG_CHANGE", "1", TYPE_BOOL, FLAG_NEW | FLAG_CLIENT_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE_MUSIC)
|
||||
};
|
||||
|
||||
#define str(s) #s
|
||||
#define V(key, flags) key, str(key), "0", TYPE_UNSIGNED_NUMBER, flags
|
||||
#define F(key, flags) key, str(key), "0", TYPE_FLOAT, flags
|
||||
|
||||
array<shared_ptr<PropertyDescription>, ConnectionProperties::CONNECTION_ENDMARKER> connection_info = {
|
||||
make_shared<PropertyDescription>(CONNECTION_UNDEFINED, "CONNECTION_UNDEFINED", "undefined", TYPE_UNKNOWN, 0),
|
||||
make_shared<PropertyDescription>(CONNECTION_PING, "CONNECTION_PING", "0", TYPE_UNSIGNED_NUMBER, 0), //average latency for a round trip through and back this connection
|
||||
make_shared<PropertyDescription>(CONNECTION_PING_DEVIATION, "CONNECTION_PING_DEVIATION", "0", TYPE_UNSIGNED_NUMBER, 0), //standard deviation of the above average latency
|
||||
make_shared<PropertyDescription>(CONNECTION_CONNECTED_TIME, "CONNECTION_CONNECTED_TIME", "0", TYPE_UNSIGNED_NUMBER, 0), //how long the connection exists already
|
||||
make_shared<PropertyDescription>(CONNECTION_IDLE_TIME, "CONNECTION_IDLE_TIME", "0", TYPE_UNSIGNED_NUMBER, 0), //how long since the last action of this manager
|
||||
make_shared<PropertyDescription>(CONNECTION_CLIENT_IP, "CONNECTION_CLIENT_IP", "", TYPE_STRING, FLAG_SAVE), //NEED DB SAVE! //IP of this manager (as seen from the server side)
|
||||
make_shared<PropertyDescription>(CONNECTION_CLIENT_PORT, "CONNECTION_CLIENT_PORT", "0", TYPE_UNSIGNED_NUMBER, 0), //Port of this manager (as seen from the server side)
|
||||
make_shared<PropertyDescription>(CONNECTION_SERVER_IP, "CONNECTION_SERVER_IP", "", TYPE_STRING, 0), //IP of the server (seen from the manager side) - only available on yourself, not for remote clients, not available server side
|
||||
make_shared<PropertyDescription>(CONNECTION_SERVER_PORT, "CONNECTION_SERVER_PORT", "0", TYPE_UNSIGNED_NUMBER, 0), //Port of the server (seen from the manager side) - only available on yourself, not for remote clients, not available server side
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_SENT_SPEECH, 0)), //how many Speech packets were sent through this connection
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_SENT_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_SENT_CONTROL,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_SENT_TOTAL, FLAG_CLIENT_INFO)), //how many packets were sent totally (this is PACKETS_SENT_SPEECH + PACKETS_SENT_KEEPALIVE + PACKETS_SENT_CONTROL)
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_SENT_SPEECH, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_SENT_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_SENT_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_SENT_TOTAL, FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_RECEIVED_SPEECH, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_RECEIVED_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_RECEIVED_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_PACKETS_RECEIVED_TOTAL, FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_RECEIVED_SPEECH, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_RECEIVED_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_RECEIVED_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BYTES_RECEIVED_TOTAL, FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_PACKETLOSS_SPEECH, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_PACKETLOSS_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_PACKETLOSS_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_PACKETLOSS_TOTAL, FLAG_CLIENT_INFO)), //the probability with which a packet round trip failed because a packet was lost
|
||||
make_shared<PropertyDescription>(F(CONNECTION_SERVER2CLIENT_PACKETLOSS_SPEECH, 0)), //the probability with which a speech packet failed from the server to the manager
|
||||
make_shared<PropertyDescription>(F(CONNECTION_SERVER2CLIENT_PACKETLOSS_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_SERVER2CLIENT_PACKETLOSS_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_SERVER2CLIENT_PACKETLOSS_TOTAL, FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_CLIENT2SERVER_PACKETLOSS_SPEECH, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_CLIENT2SERVER_PACKETLOSS_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_CLIENT2SERVER_PACKETLOSS_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(F(CONNECTION_CLIENT2SERVER_PACKETLOSS_TOTAL, FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_SPEECH, 0)), //howmany bytes of speech packets we sent during the last second
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_KEEPALIVE, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_CONTROL, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_TOTAL,FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_SPEECH,0)), //howmany bytes/s of speech packets we sent in average during the last minute
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_KEEPALIVE,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_CONTROL,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_TOTAL,FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_SPEECH, 0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_KEEPALIVE,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_CONTROL,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_TOTAL,FLAG_CLIENT_INFO)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_SPEECH,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_KEEPALIVE,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_CONTROL,0)),
|
||||
make_shared<PropertyDescription>(V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_TOTAL,FLAG_CLIENT_INFO)),
|
||||
|
||||
//Rare properties
|
||||
make_shared<PropertyDescription>(V(CONNECTION_FILETRANSFER_BANDWIDTH_SENT, FLAG_CLIENT_INFO)), //how many bytes per second are currently being sent by file transfers
|
||||
make_shared<PropertyDescription>(V(CONNECTION_FILETRANSFER_BANDWIDTH_RECEIVED, FLAG_CLIENT_INFO)), //how many bytes per second are currently being received by file transfers
|
||||
make_shared<PropertyDescription>(V(CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL, FLAG_CLIENT_INFO)), //how many bytes we received in total through file transfers
|
||||
make_shared<PropertyDescription>(V(CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL, FLAG_CLIENT_INFO)) //how many bytes we sent in total through file transfers
|
||||
};
|
||||
|
||||
array<shared_ptr<PropertyDescription>, InstanceProperties::SERVERINSTANCE_ENDMARKER> instance_info = {
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_UNDEFINED, "SERVERINSTANCE_UNDEFINED", "undefined", TYPE_UNKNOWN, 0),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_DATABASE_VERSION, "SERVERINSTANCE_DATABASE_VERSION", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_PERMISSIONS_VERSION, "SERVERINSTANCE_PERMISSIONS_VERSION", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_FILETRANSFER_HOST, "SERVERINSTANCE_FILETRANSFER_HOST", "0.0.0.0,[::]", TYPE_STRING, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_FILETRANSFER_PORT, "SERVERINSTANCE_FILETRANSFER_PORT", "30303", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_FILETRANSFER_MAX_CONNECTIONS, "SERVERINSTANCE_FILETRANSFER_MAX_CONNECTIONS", "100", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_FILETRANSFER_MAX_CONNECTIONS_PER_IP, "SERVERINSTANCE_FILETRANSFER_MAX_CONNECTIONS_PER_IP", "20", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_QUERY_HOST, "SERVERINSTANCE_QUERY_HOST", "0.0.0.0,[::]", TYPE_STRING, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_QUERY_PORT, "SERVERINSTANCE_QUERY_PORT", "10101", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_QUERY_MAX_CONNECTIONS, "SERVERINSTANCE_QUERY_MAX_CONNECTIONS", "100", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_QUERY_MAX_CONNECTIONS_PER_IP, "SERVERINSTANCE_QUERY_MAX_CONNECTIONS_PER_IP", "3", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_MONTHLY_TIMESTAMP, "SERVERINSTANCE_MONTHLY_TIMESTAMP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_MAX_DOWNLOAD_TOTAL_BANDWIDTH, "SERVERINSTANCE_MAX_DOWNLOAD_TOTAL_BANDWIDTH", "-1", TYPE_SIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_MAX_UPLOAD_TOTAL_BANDWIDTH, "SERVERINSTANCE_MAX_UPLOAD_TOTAL_BANDWIDTH", "-1", TYPE_SIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SERVERQUERY_FLOOD_COMMANDS, "SERVERINSTANCE_SERVERQUERY_FLOOD_COMMANDS", "3", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE), //how many commands we can issue while in the SERVERINSTANCE_SERVERQUERY_FLOOD_TIME window
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SERVERQUERY_FLOOD_TIME, "SERVERINSTANCE_SERVERQUERY_FLOOD_TIME", "1", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE), //time window in seconds for max command execution check
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SERVERQUERY_BAN_TIME, "SERVERINSTANCE_SERVERQUERY_BAN_TIME", "600", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE), //how many seconds someone get banned if he floods
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP, "SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP, "SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP, "SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP, "SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP, "SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_GUEST_SERVERQUERY_GROUP, "SERVERINSTANCE_GUEST_SERVERQUERY_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP, "SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_PENDING_CONNECTIONS_PER_IP, "SERVERINSTANCE_PENDING_CONNECTIONS_PER_IP", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SPOKEN_TIME_TOTAL, "SERVERINSTANCE_SPOKEN_TIME_TOTAL", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SPOKEN_TIME_DELETED, "SERVERINSTANCE_SPOKEN_TIME_DELETED", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SPOKEN_TIME_ALIVE, "SERVERINSTANCE_SPOKEN_TIME_ALIVE", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_SPOKEN_TIME_VARIANZ, "SERVERINSTANCE_SPOKEN_TIME_VARIANZ", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_VIRTUAL_SERVER_ID_INDEX, "SERVERINSTANCE_VIRTUAL_SERVER_ID_INDEX", "1", TYPE_UNSIGNED_NUMBER, FLAG_SAVE | FLAG_INSTANCE_VARIABLE | FLAG_NEW),
|
||||
make_shared<PropertyDescription>(SERVERINSTANCE_UNIQUE_ID, "SERVERINSTANCE_UNIQUE_ID", "", TYPE_STRING, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW),
|
||||
};
|
||||
|
||||
|
||||
array<shared_ptr<PropertyDescription>, PlaylistProperties::PLAYLIST_ENDMARKER> playlist_info = {
|
||||
make_shared<PropertyDescription>(PLAYLIST_UNDEFINED, "PLAYLIST_UNDEFINED", "undefined", TYPE_UNKNOWN, 0),
|
||||
make_shared<PropertyDescription>(PLAYLIST_ID, "PLAYLIST_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_TYPE, "PLAYLIST_TYPE", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_TITLE, "PLAYLIST_TITLE", "Yet another playlist", TYPE_STRING, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_DESCRIPTION, "PLAYLIST_DESCRIPTION", "", TYPE_STRING, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_OWNER_DBID, "PLAYLIST_OWNER_DBID", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_OWNER_NAME, "PLAYLIST_OWNER_NAME", "0", TYPE_STRING, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_FLAG_DELETE_PLAYED, "PLAYLIST_FLAG_DELETE_PLAYED", "1", TYPE_BOOL, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_REPLAY_MODE, "PLAYLIST_REPLAY_MODE", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_CURRENT_SONG_ID, "PLAYLIST_CURRENT_SONG_ID", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_FLAG_FINISHED, "PLAYLIST_FLAG_FINISHED", "0", TYPE_BOOL, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE),
|
||||
make_shared<PropertyDescription>(PLAYLIST_MAX_SONGS, "PLAYLIST_MAX_SONGS", "-1", TYPE_SIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE),
|
||||
};
|
||||
|
||||
shared_ptr<PropertyDescription> PropertyDescription::unknown = make_shared<PropertyDescription>(UNKNOWN_UNDEFINED, "undefined", "", ValueType::TYPE_UNKNOWN, 0);
|
||||
namespace impl {
|
||||
#define M(type, _info) \
|
||||
template <> \
|
||||
const std::shared_ptr<property::PropertyDescription>& info<type>(type type) { \
|
||||
for(const auto& element : (_info)) \
|
||||
if(element->property_index == (type)) \
|
||||
return element; \
|
||||
return (_info)[0]; \
|
||||
} \
|
||||
\
|
||||
template <> \
|
||||
const std::shared_ptr<property::PropertyDescription>& info<type>(const std::string& _type) { \
|
||||
for(const auto& element : (_info)) \
|
||||
if(element->name == _type) \
|
||||
return element; \
|
||||
return (_info)[0]; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template <> \
|
||||
std::deque<std::shared_ptr<property::PropertyDescription>> list<type>() { \
|
||||
return {_info.begin(), _info.end()}; \
|
||||
}
|
||||
|
||||
M(VirtualServerProperties, virtualserver_info);
|
||||
M(ChannelProperties, channel_info);
|
||||
M(GroupProperties, group_info);
|
||||
M(ClientProperties, client_info);
|
||||
M(ConnectionProperties, connection_info);
|
||||
M(InstanceProperties, instance_info);
|
||||
M(PlaylistProperties, playlist_info);
|
||||
|
||||
|
||||
#define TP(info) \
|
||||
{ for(const auto& prop : (info)) \
|
||||
if(prop->name == key) return prop; }
|
||||
|
||||
const std::shared_ptr<property::PropertyDescription>& info_key(const std::string& key) {
|
||||
TP(virtualserver_info);
|
||||
TP(channel_info);
|
||||
TP(group_info);
|
||||
TP(client_info);
|
||||
TP(connection_info);
|
||||
TP(instance_info);
|
||||
TP(playlist_info);
|
||||
return PropertyDescription::unknown;
|
||||
}
|
||||
|
||||
|
||||
const std::shared_ptr<property::PropertyDescription>& info_key(PropertyType type, const std::string& key) {
|
||||
if(type == PropertyType::PROP_TYPE_SERVER)
|
||||
TP(virtualserver_info)
|
||||
else if(type == PropertyType::PROP_TYPE_CHANNEL)
|
||||
TP(channel_info)
|
||||
else if(type == PropertyType::PROP_TYPE_CLIENT)
|
||||
TP(client_info)
|
||||
else if(type == PropertyType::PROP_TYPE_GROUP)
|
||||
TP(group_info)
|
||||
else if(type == PropertyType::PROP_TYPE_CONNECTION)
|
||||
TP(connection_info)
|
||||
else if(type == PropertyType::PROP_TYPE_INSTANCE)
|
||||
TP(instance_info)
|
||||
else if(type == PropertyType::PROP_TYPE_PLAYLIST)
|
||||
TP(playlist_info);
|
||||
return PropertyDescription::unknown;
|
||||
}
|
||||
|
||||
const std::shared_ptr<property::PropertyDescription>& info(PropertyType type, int index) {
|
||||
if(type == PropertyType::PROP_TYPE_SERVER)
|
||||
return impl::info<VirtualServerProperties>((VirtualServerProperties) index);
|
||||
else if(type == PropertyType::PROP_TYPE_CHANNEL)
|
||||
return impl::info<ChannelProperties>((ChannelProperties) index);
|
||||
else if(type == PropertyType::PROP_TYPE_CLIENT)
|
||||
return impl::info<ClientProperties>((ClientProperties) index);
|
||||
else if(type == PropertyType::PROP_TYPE_GROUP)
|
||||
return impl::info<GroupProperties>((GroupProperties) index);
|
||||
else if(type == PropertyType::PROP_TYPE_CONNECTION)
|
||||
return impl::info<ConnectionProperties>((ConnectionProperties) index);
|
||||
else if(type == PropertyType::PROP_TYPE_INSTANCE)
|
||||
return impl::info<InstanceProperties>((InstanceProperties) index);
|
||||
else if(type == PropertyType::PROP_TYPE_PLAYLIST)
|
||||
return impl::info<PlaylistProperties>((PlaylistProperties) index);
|
||||
return PropertyDescription::unknown;
|
||||
}
|
||||
|
||||
#define M1(info) \
|
||||
for(const auto& e : (info)){ \
|
||||
auto found = find(used.begin(), used.end(), e->name); \
|
||||
if(found != used.end()) { \
|
||||
cerr << "[CRITICAL] Double registered property! (" << e->name << ")" << endl; \
|
||||
return false; \
|
||||
} \
|
||||
used.push_back(e->name); \
|
||||
}
|
||||
|
||||
bool validateUnique() {
|
||||
deque<string> used;
|
||||
M1(virtualserver_info);
|
||||
M1(channel_info);
|
||||
M1(group_info);
|
||||
M1(client_info);
|
||||
M1(connection_info);
|
||||
M1(instance_info);
|
||||
M1(playlist_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateInput(const std::string& input, ValueType type) {
|
||||
if(type == ValueType::TYPE_UNKNOWN) return true;
|
||||
else if(type == ValueType::TYPE_UNSIGNED_NUMBER) {
|
||||
|
409
src/Properties.h
409
src/Properties.h
@ -1,7 +1,6 @@
|
||||
#include <utility>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "misc/memtracker.h"
|
||||
#include <ThreadPool/Mutex.h>
|
||||
#include "Variable.h"
|
||||
@ -9,17 +8,23 @@
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <array>
|
||||
|
||||
#include "misc/spin_lock.h"
|
||||
#include "converters/converter.h"
|
||||
|
||||
#define PROPS_DEFINED
|
||||
namespace ts {
|
||||
#ifdef NDEBUG
|
||||
#define EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
#endif
|
||||
|
||||
#define PROPERTIES_DEFINED
|
||||
|
||||
namespace ts {
|
||||
namespace property {
|
||||
enum PropertyType {
|
||||
PROP_TYPE_SERVER = 0,
|
||||
@ -29,8 +34,10 @@ namespace ts {
|
||||
PROP_TYPE_INSTANCE = 4,
|
||||
PROP_TYPE_CONNECTION = 5,
|
||||
PROP_TYPE_PLAYLIST = 6,
|
||||
PROP_TYPE_UNKNOWN = 7
|
||||
PROP_TYPE_UNKNOWN = 7,
|
||||
PROP_TYPE_MAX
|
||||
};
|
||||
|
||||
static constexpr const char *PropertyType_Names[7] = {
|
||||
"SERVER",
|
||||
"CHANNEL",
|
||||
@ -134,17 +141,17 @@ namespace ts {
|
||||
VIRTUALSERVER_MAXCLIENTS, //only available on request (=> requestServerVariables), stores the maximum number of clients that may currently join the server
|
||||
VIRTUALSERVER_PASSWORD, //not available to clients, the server password
|
||||
VIRTUALSERVER_CLIENTS_ONLINE, //only available on request (=> requestServerVariables),
|
||||
VIRTUALSERVER_QUERYCLIENTS_ONLINE, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_CHANNELS_ONLINE, //only available on request (=> requestServerVariables),
|
||||
VIRTUALSERVER_CREATED, //available when connected, stores the time when the server was created
|
||||
VIRTUALSERVER_UPTIME, //only available on request (=> requestServerVariables), the time since the server was started
|
||||
VIRTUALSERVER_CODEC_ENCRYPTION_MODE, //available and always up-to-date when connected
|
||||
|
||||
//Rare properties
|
||||
VIRTUALSERVER_CODEC_ENCRYPTION_MODE, //available and always up-to-date when connected
|
||||
VIRTUALSERVER_KEYPAIR, //internal use
|
||||
VIRTUALSERVER_HOSTMESSAGE, //available when connected, not updated while connected
|
||||
VIRTUALSERVER_HOSTMESSAGE_MODE, //available when connected, not updated while connected
|
||||
VIRTUALSERVER_FILEBASE, //not available to clients, stores the folder used for file transfers
|
||||
VIRTUALSERVER_DEFAULT_SERVER_GROUP, //the manager permissions server group that a new client gets assigned
|
||||
VIRTUALSERVER_DEFAULT_SERVER_GROUP, //the client permissions server group that a new client gets assigned
|
||||
VIRTUALSERVER_DEFAULT_MUSIC_GROUP, //the client permissions server group that a new client gets assigned
|
||||
VIRTUALSERVER_DEFAULT_CHANNEL_GROUP, //the channel permissions group that a new client gets assigned when joining a channel
|
||||
VIRTUALSERVER_FLAG_PASSWORD, //only available on request (=> requestServerVariables)
|
||||
@ -154,6 +161,7 @@ namespace ts {
|
||||
VIRTUALSERVER_HOSTBANNER_URL, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_HOSTBANNER_GFX_URL, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_HOSTBANNER_GFX_INTERVAL, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_HOSTBANNER_MODE, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_COMPLAIN_AUTOBAN_COUNT, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_COMPLAIN_AUTOBAN_TIME, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_COMPLAIN_REMOVE_TIME, //only available on request (=> requestServerVariables)
|
||||
@ -168,7 +176,6 @@ namespace ts {
|
||||
VIRTUALSERVER_HOSTBUTTON_TOOLTIP, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_HOSTBUTTON_URL, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_HOSTBUTTON_GFX_URL, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_QUERYCLIENTS_ONLINE, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_DOWNLOAD_QUOTA, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_UPLOAD_QUOTA, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_MONTH_BYTES_DOWNLOADED, //only available on request (=> requestServerVariables)
|
||||
@ -176,6 +183,7 @@ namespace ts {
|
||||
VIRTUALSERVER_TOTAL_BYTES_DOWNLOADED, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_TOTAL_BYTES_UPLOADED, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_PORT, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_HOST, //internal use | contains comma separated ip list
|
||||
VIRTUALSERVER_AUTOSTART, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_MACHINE_ID, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL, //only available on request (=> requestServerVariables)
|
||||
@ -185,7 +193,6 @@ namespace ts {
|
||||
VIRTUALSERVER_LOG_PERMISSIONS, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_LOG_SERVER, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_LOG_FILETRANSFER, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_MIN_CLIENT_VERSION, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_NAME_PHONETIC, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_ICON_ID, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_RESERVED_SLOTS, //available when connected, always up-to-date
|
||||
@ -194,12 +201,11 @@ namespace ts {
|
||||
VIRTUALSERVER_TOTAL_PACKETLOSS_CONTROL, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_TOTAL_PACKETLOSS_TOTAL, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_TOTAL_PING, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_HOST, //internal use | contains comma separated ip list
|
||||
VIRTUALSERVER_WEBLIST_ENABLED, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY, //internal use
|
||||
VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY, //available when connected
|
||||
VIRTUALSERVER_HOSTBANNER_MODE, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT, //available when connected, always up-to-date
|
||||
VIRTUALSERVER_MIN_CLIENT_VERSION, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_MIN_ANDROID_VERSION, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_MIN_IOS_VERSION, //only available on request (=> requestServerVariables)
|
||||
VIRTUALSERVER_MIN_WINPHONE_VERSION, //only available on request (=> requestServerVariables)
|
||||
@ -223,7 +229,6 @@ namespace ts {
|
||||
VIRTUALSERVER_DISABLE_IP_SAVING,
|
||||
|
||||
VIRTUALSERVER_COUNTRY_CODE,
|
||||
|
||||
VIRTUALSERVER_ENDMARKER
|
||||
};
|
||||
|
||||
@ -347,21 +352,21 @@ namespace ts {
|
||||
CLIENT_INTEGRATIONS,
|
||||
CLIENT_ACTIVE_INTEGRATIONS_INFO,
|
||||
|
||||
CLIENT_TEAFORO_ID,
|
||||
CLIENT_TEAFORO_NAME,
|
||||
CLIENT_TEAFORO_FLAGS,
|
||||
|
||||
//Music bot stuff
|
||||
CLIENT_BOT_TYPE,
|
||||
CLIENT_OWNER,
|
||||
CLIENT_PLAYER_VOLUME,
|
||||
CLIENT_BOT_TYPE,
|
||||
CLIENT_LAST_CHANNEL,
|
||||
CLIENT_PLAYER_STATE,
|
||||
CLIENT_PLAYER_VOLUME,
|
||||
CLIENT_PLAYLIST_ID,
|
||||
CLIENT_DISABLED,
|
||||
CLIENT_UPTIME_MODE,
|
||||
CLIENT_FLAG_NOTIFY_SONG_CHANGE,
|
||||
|
||||
CLIENT_TEAFORO_ID,
|
||||
CLIENT_TEAFORO_NAME,
|
||||
CLIENT_TEAFORO_FLAGS,
|
||||
|
||||
CLIENT_ENDMARKER
|
||||
};
|
||||
|
||||
@ -462,146 +467,219 @@ namespace ts {
|
||||
};
|
||||
*/
|
||||
|
||||
class PropertyDescription;
|
||||
namespace impl {
|
||||
template<typename T>
|
||||
extern std::deque<std::shared_ptr<property::PropertyDescription>> list();
|
||||
extern std::deque<std::shared_ptr<property::PropertyDescription>> list_all();
|
||||
|
||||
template<typename T>
|
||||
extern const std::shared_ptr<property::PropertyDescription> &info(T /* property */);
|
||||
|
||||
template<typename T>
|
||||
extern const std::shared_ptr<property::PropertyDescription> &info(const std::string& /* key */);
|
||||
|
||||
|
||||
extern const std::shared_ptr<property::PropertyDescription> &info_key(const std::string &);
|
||||
extern const std::shared_ptr<property::PropertyDescription> &info_key(PropertyType, const std::string &);
|
||||
extern const std::shared_ptr<property::PropertyDescription> &info(PropertyType, int);
|
||||
|
||||
template<typename V>
|
||||
inline PropertyType type() {
|
||||
std::cerr << "[CRITICAL] Invalid property type!" << std::endl;
|
||||
return PropertyType::PROP_TYPE_UNKNOWN;
|
||||
constexpr inline auto property_count() {
|
||||
size_t result{0};
|
||||
result += VIRTUALSERVER_ENDMARKER;
|
||||
result += CHANNEL_ENDMARKER;
|
||||
result += CLIENT_ENDMARKER;
|
||||
result += GROUP_ENDMARKER;
|
||||
result += SERVERINSTANCE_ENDMARKER;
|
||||
result += CONNECTION_ENDMARKER;
|
||||
result += PLAYLIST_ENDMARKER;
|
||||
result += UNKNOWN_ENDMARKER;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<VirtualServerProperties>() { return PropertyType::PROP_TYPE_SERVER; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<ChannelProperties>() { return PropertyType::PROP_TYPE_CHANNEL; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<ClientProperties>() { return PropertyType::PROP_TYPE_CLIENT; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<ConnectionProperties>() { return PropertyType::PROP_TYPE_CONNECTION; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<GroupProperties>() { return PropertyType::PROP_TYPE_GROUP; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<InstanceProperties>() { return PropertyType::PROP_TYPE_INSTANCE; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<PlaylistProperties>() { return PropertyType::PROP_TYPE_PLAYLIST; }
|
||||
|
||||
template<>
|
||||
constexpr inline PropertyType type<UnknownProperties>() { return PropertyType::PROP_TYPE_UNKNOWN; }
|
||||
|
||||
inline size_t length(PropertyType type) {
|
||||
switch (type) {
|
||||
case PROP_TYPE_SERVER:
|
||||
return VIRTUALSERVER_ENDMARKER - VIRTUALSERVER_BEGINMARKER;
|
||||
case PROP_TYPE_CHANNEL:
|
||||
return CHANNEL_ENDMARKER - CHANNEL_BEGINMARKER;
|
||||
case PROP_TYPE_CLIENT:
|
||||
return CLIENT_ENDMARKER - CLIENT_BEGINMARKER;
|
||||
case PROP_TYPE_CONNECTION:
|
||||
return CONNECTION_ENDMARKER - CONNECTION_BEGINMARKER;
|
||||
case PROP_TYPE_GROUP:
|
||||
return GROUP_ENDMARKER - GROUP_BEGINMARKER;
|
||||
case PROP_TYPE_INSTANCE:
|
||||
return SERVERINSTANCE_ENDMARKER - SERVERINSTANCE_BEGINMARKER;
|
||||
case PROP_TYPE_PLAYLIST:
|
||||
return PLAYLIST_ENDMARKER - PLAYLIST_BEGINMARKER;
|
||||
case PROP_TYPE_UNKNOWN:
|
||||
return UNKNOWN_ENDMARKER - UNKNOWN_BEGINMARKER;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t offset(PropertyType type) {
|
||||
switch (type) {
|
||||
case PROP_TYPE_SERVER:
|
||||
return VIRTUALSERVER_BEGINMARKER;
|
||||
case PROP_TYPE_CHANNEL:
|
||||
return CHANNEL_BEGINMARKER;
|
||||
case PROP_TYPE_CLIENT:
|
||||
return CLIENT_BEGINMARKER;
|
||||
case PROP_TYPE_CONNECTION:
|
||||
return CONNECTION_BEGINMARKER;
|
||||
case PROP_TYPE_GROUP:
|
||||
return GROUP_BEGINMARKER;
|
||||
case PROP_TYPE_INSTANCE:
|
||||
return SERVERINSTANCE_BEGINMARKER;
|
||||
case PROP_TYPE_PLAYLIST:
|
||||
return PLAYLIST_BEGINMARKER;
|
||||
case PROP_TYPE_UNKNOWN:
|
||||
return UNKNOWN_BEGINMARKER;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern bool validateUnique();
|
||||
|
||||
extern bool validateInput(const std::string &, ValueType);
|
||||
extern bool validateInput(const std::string& input, ValueType type);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
constexpr inline PropertyType type_from_enum();
|
||||
|
||||
template<typename T>
|
||||
inline const std::shared_ptr<property::PropertyDescription> &info(T property) { return impl::info<T>(property); }
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<VirtualServerProperties>() { return PropertyType::PROP_TYPE_SERVER; }
|
||||
|
||||
template<typename T>
|
||||
inline const std::shared_ptr<property::PropertyDescription> &info(const std::string& key) { return impl::info<T>(key); }
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<ChannelProperties>() { return PropertyType::PROP_TYPE_CHANNEL; }
|
||||
|
||||
class PropertyDescription {
|
||||
public:
|
||||
static std::shared_ptr<PropertyDescription> unknown;
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<ClientProperties>() { return PropertyType::PROP_TYPE_CLIENT; }
|
||||
|
||||
std::string name;
|
||||
std::string default_value;
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<ConnectionProperties>() { return PropertyType::PROP_TYPE_CONNECTION; }
|
||||
|
||||
ValueType type_value = property::ValueType::TYPE_UNKNOWN;
|
||||
PropertyType type_property = PropertyType::PROP_TYPE_UNKNOWN;
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<GroupProperties>() { return PropertyType::PROP_TYPE_GROUP; }
|
||||
|
||||
int property_index = 0;
|
||||
flag_type flags = 0;
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<InstanceProperties>() { return PropertyType::PROP_TYPE_INSTANCE; }
|
||||
|
||||
PropertyDescription(int property_id, PropertyType property_type, const std::string &name, const std::string &default_value, property::ValueType type, flag_type flags) noexcept;
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<PlaylistProperties>() { return PropertyType::PROP_TYPE_PLAYLIST; }
|
||||
|
||||
template<typename T>
|
||||
PropertyDescription(T property, const std::string &name, const std::string &default_value, property::ValueType type, flag_type flags) noexcept : PropertyDescription((int) property, impl::type<T>(), name, default_value, type, flags) {}
|
||||
template<>
|
||||
constexpr inline PropertyType type_from_enum<UnknownProperties>() { return PropertyType::PROP_TYPE_UNKNOWN; }
|
||||
|
||||
inline bool operator==(const PropertyDescription& other) const {
|
||||
return other.property_index == this->property_index && other.type_property == this->type_property;
|
||||
}
|
||||
struct PropertyDescription {
|
||||
std::string_view name{};
|
||||
std::string_view default_value{};
|
||||
|
||||
inline bool operator==(const std::shared_ptr<PropertyDescription>& other) const {
|
||||
return this->operator==(*other);
|
||||
}
|
||||
//TODO: Rename these sucky variables
|
||||
ValueType type_value{property::ValueType::TYPE_UNKNOWN};
|
||||
PropertyType type_property{PropertyType::PROP_TYPE_UNKNOWN};
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
inline bool operator==(const T& type) const {
|
||||
return this->property_index == type && impl::type<T>() == this->type_property;
|
||||
}
|
||||
int property_index{0};
|
||||
flag_type flags{0};
|
||||
|
||||
inline bool validate_input(const std::string& input) {
|
||||
return impl::validateInput(input, this->type_value);
|
||||
}
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
constexpr PropertyDescription(PropertyEnumType property, std::string_view name, std::string_view default_value, property::ValueType value_type, flag_type flags) noexcept
|
||||
: name{name}, default_value{default_value}, type_value{value_type}, type_property{type_from_enum<PropertyEnumType>()},
|
||||
property_index{(int) property}, flags{flags} { }
|
||||
PropertyDescription(const PropertyDescription&) = delete;
|
||||
PropertyDescription(PropertyDescription&&) = default;
|
||||
|
||||
constexpr inline bool operator==(const PropertyDescription& other) const {
|
||||
return this->property_index == other.property_index && this->type_property == other.type_property;
|
||||
}
|
||||
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
constexpr inline bool operator==(const PropertyEnumType& other) const {
|
||||
return this->property_index == (int) other && this->type_property == type_from_enum<PropertyEnumType>();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool is_undefined() const { return property_index == 0; }
|
||||
[[nodiscard]] inline bool validate_input(const std::string& value) const { return impl::validateInput(value, this->type_value); }
|
||||
};
|
||||
constexpr static PropertyDescription undefined_property_description{UnknownProperties::UNKNOWN_UNDEFINED, "undefined", "", ValueType::TYPE_UNKNOWN, 0};
|
||||
|
||||
struct PropertyListInfo {
|
||||
std::array<size_t, PropertyType::PROP_TYPE_MAX> begin_index{}; /* inclusive */
|
||||
std::array<size_t, PropertyType::PROP_TYPE_MAX> end_index{}; /* exclusive */
|
||||
};
|
||||
|
||||
#ifdef EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
extern std::array<PropertyDescription, impl::property_count()> property_list;
|
||||
#else
|
||||
#include "./PropertyDefinition.h"
|
||||
|
||||
constexpr inline auto property_count() {
|
||||
return property_list.size();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
#define const_modifier
|
||||
#else
|
||||
#define const_modifier constexpr
|
||||
#endif
|
||||
namespace impl {
|
||||
const_modifier inline size_t property_type_begin(PropertyType type) {
|
||||
size_t index{0};
|
||||
for(; index < property_list.size(); index++)
|
||||
if(property_list[index].type_property == type)
|
||||
return index;
|
||||
return property_list.size();
|
||||
}
|
||||
|
||||
const_modifier inline size_t property_type_end(size_t begin, PropertyType type) {
|
||||
size_t index{begin};
|
||||
for(; index < property_list.size() - 1; index++)
|
||||
if(property_list[index + 1].type_property != type)
|
||||
return index + 1;
|
||||
return property_list.size();
|
||||
}
|
||||
|
||||
const_modifier inline PropertyListInfo list_info() noexcept {
|
||||
std::array<size_t, PropertyType::PROP_TYPE_MAX> begin_index{
|
||||
/* We're using numbers here so we don't mess up the order. This would be fatal */
|
||||
property_type_begin((PropertyType) 0),
|
||||
property_type_begin((PropertyType) 1),
|
||||
property_type_begin((PropertyType) 2),
|
||||
property_type_begin((PropertyType) 3),
|
||||
property_type_begin((PropertyType) 4),
|
||||
property_type_begin((PropertyType) 5),
|
||||
property_type_begin((PropertyType) 6),
|
||||
property_type_begin((PropertyType) 7)
|
||||
};
|
||||
|
||||
return {
|
||||
begin_index,
|
||||
std::array<size_t, PropertyType::PROP_TYPE_MAX>{
|
||||
/* We're using numbers here so we don't mess up the order. This would be fatal */
|
||||
property_type_end(begin_index[0], (PropertyType) 0),
|
||||
property_type_end(begin_index[1], (PropertyType) 1),
|
||||
property_type_end(begin_index[2], (PropertyType) 2),
|
||||
property_type_end(begin_index[3], (PropertyType) 3),
|
||||
property_type_end(begin_index[4], (PropertyType) 4),
|
||||
property_type_end(begin_index[5], (PropertyType) 5),
|
||||
property_type_end(begin_index[6], (PropertyType) 6),
|
||||
property_type_end(begin_index[7], (PropertyType) 7)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
#ifdef EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
extern const PropertyListInfo property_list_info;
|
||||
#else
|
||||
constexpr auto property_list_info = impl::list_info();
|
||||
#endif
|
||||
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
const_modifier inline const auto& describe(PropertyEnumType type) {
|
||||
static_assert(type_from_enum<PropertyEnumType>() < property_list_info.end_index.size());
|
||||
const auto begin = property_list_info.begin_index[type_from_enum<PropertyEnumType>()];
|
||||
const auto end = property_list_info.end_index[type_from_enum<PropertyEnumType>()];
|
||||
const auto idx = begin + (size_t) type;
|
||||
if(idx >= end) return undefined_property_description;
|
||||
return property_list[idx];
|
||||
}
|
||||
|
||||
inline const auto& describe(PropertyType type, size_t index) {
|
||||
if(type >= property_list_info.end_index.size()) return undefined_property_description;
|
||||
const auto begin = property_list_info.begin_index[type];
|
||||
const auto end = property_list_info.end_index[type];
|
||||
const auto idx = begin + index;
|
||||
if(idx >= end) return undefined_property_description;
|
||||
return property_list[idx];
|
||||
}
|
||||
|
||||
inline const auto& find(PropertyType type, const std::string_view& name) {
|
||||
if(type >= property_list_info.end_index.size()) return undefined_property_description;
|
||||
|
||||
constexpr static auto buffer_size{128}; /* no property is longer than 128 bytes */
|
||||
if(name.size() >= buffer_size) return undefined_property_description;
|
||||
char buffer[buffer_size];
|
||||
for(size_t index{0}; index < name.size(); index++)
|
||||
buffer[index] = (char) tolower(name[index]);
|
||||
|
||||
const std::string_view lower_name{buffer, name.size()};
|
||||
const auto begin = property_list_info.begin_index[type];
|
||||
const auto end = property_list_info.end_index[type];
|
||||
for(size_t index{begin}; index < end; index++)
|
||||
if(property_list[index].name == lower_name)
|
||||
return property_list[index];
|
||||
return property_list[begin]; /* begin index MUST be the undefined */
|
||||
}
|
||||
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
inline const auto& find(const std::string_view& name) {
|
||||
return find(type_from_enum<PropertyEnumType>(), name);
|
||||
}
|
||||
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
inline std::vector<const PropertyDescription*> list() {
|
||||
constexpr auto type = type_from_enum<PropertyEnumType>();
|
||||
if(type >= property_list_info.end_index.size()) return {};
|
||||
|
||||
const auto begin = property_list_info.begin_index[type];
|
||||
const auto end = property_list_info.end_index[type];
|
||||
return {property_list.begin() + begin, property_list.begin() + end};
|
||||
}
|
||||
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
const_modifier inline const std::string_view& name(PropertyEnumType type) { /* defining the return type here to help out my IDE a bit ;) */
|
||||
return describe<PropertyEnumType>(type).name;
|
||||
}
|
||||
|
||||
template <typename PropertyEnumType, typename std::enable_if<std::is_enum<PropertyEnumType>::value, int>::type = 0>
|
||||
const_modifier inline size_t property_count() {
|
||||
const auto begin = property_list_info.begin_index[type_from_enum<PropertyEnumType>()];
|
||||
const auto end = property_list_info.end_index[type_from_enum<PropertyEnumType>()];
|
||||
return end - begin;
|
||||
}
|
||||
|
||||
#undef const_modifier
|
||||
}
|
||||
class Properties;
|
||||
|
||||
@ -609,7 +687,7 @@ namespace ts {
|
||||
spin_lock value_lock;
|
||||
std::any casted_value;
|
||||
std::string value;
|
||||
std::shared_ptr<property::PropertyDescription> description;
|
||||
const property::PropertyDescription* description;
|
||||
|
||||
bool flag_db_reference;
|
||||
bool flag_modified;
|
||||
@ -622,7 +700,6 @@ namespace ts {
|
||||
struct PropertyBundle {
|
||||
property::PropertyType type;
|
||||
size_t length;
|
||||
size_t offset;
|
||||
PropertyData properties[0];
|
||||
};
|
||||
#ifdef WIN32
|
||||
@ -672,14 +749,14 @@ namespace ts {
|
||||
PropertyWrapper&operator+=(int64_t val){ return operator=(as<int64_t>() + val); }
|
||||
PropertyWrapper&operator+=(uint64_t val){ return operator=(as<uint64_t>() + val); }
|
||||
|
||||
bool hasDbReference() const { return this->data_ptr->flag_db_reference; }
|
||||
[[nodiscard]] bool hasDbReference() const { return this->data_ptr->flag_db_reference; }
|
||||
void setDbReference(bool flag){ this->data_ptr->flag_db_reference = flag; }
|
||||
|
||||
bool isModified() const { return this->data_ptr->flag_modified; }
|
||||
[[nodiscard]] bool isModified() const { return this->data_ptr->flag_modified; }
|
||||
void setModified(bool flag){ this->data_ptr->flag_modified = flag; }
|
||||
|
||||
template <typename T>
|
||||
T as() const {
|
||||
[[nodiscard]] T as() const {
|
||||
static_assert(ts::converter<T>::supported, "as<T> isn't supported for type");
|
||||
|
||||
return PropertyAccess<T>::get(this->data_ptr);
|
||||
@ -687,10 +764,10 @@ namespace ts {
|
||||
|
||||
|
||||
template <typename T>
|
||||
operator T(){ return this->as<T>(); }
|
||||
[[nodiscard]] operator T(){ return this->as<T>(); }
|
||||
|
||||
template <typename T>
|
||||
T as_save() const {
|
||||
[[nodiscard]] T as_save() const {
|
||||
try {
|
||||
std::lock_guard lock(this->data_ptr->value_lock);
|
||||
if(this->data_ptr->casted_value.type() == typeid(T))
|
||||
@ -703,9 +780,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const property::PropertyDescription& type() const { return *this->data_ptr->description; }
|
||||
std::string value() const {
|
||||
std::lock_guard lock(this->data_ptr->value_lock);
|
||||
[[nodiscard]] const property::PropertyDescription& type() const { return *this->data_ptr->description; }
|
||||
[[nodiscard]] std::string value() const {
|
||||
std::lock_guard lock{this->data_ptr->value_lock};
|
||||
return this->data_ptr->value;
|
||||
}
|
||||
|
||||
@ -721,7 +798,7 @@ namespace ts {
|
||||
this->trigger_update();
|
||||
}
|
||||
|
||||
std::string default_value() const {
|
||||
[[nodiscard]] const std::string_view& default_value() const {
|
||||
return this->type().default_value;
|
||||
}
|
||||
|
||||
@ -762,9 +839,9 @@ namespace ts {
|
||||
|
||||
void trigger_update();
|
||||
|
||||
PropertyWrapper(Properties* /* handle */, PropertyData* /* ptr */, const std::shared_ptr<PropertyBundle>& /* bundle */);
|
||||
PropertyWrapper(Properties* /* handle */, PropertyData* /* ptr */, std::shared_ptr<PropertyBundle> /* bundle */);
|
||||
|
||||
inline Properties* get_handle() { return this->handle; }
|
||||
[[nodiscard]] inline Properties* get_handle() { return this->handle; }
|
||||
private:
|
||||
Properties* handle = nullptr;
|
||||
PropertyData* data_ptr = nullptr;
|
||||
@ -779,30 +856,30 @@ namespace ts {
|
||||
Properties();
|
||||
~Properties();
|
||||
Properties(const Properties&) = delete;
|
||||
Properties(Properties&&) = delete;
|
||||
Properties(Properties&&) = default;
|
||||
|
||||
std::vector<PropertyWrapper> list_properties(property::flag_type flagMask = (property::flag_type) ~0UL, property::flag_type negatedFlagMask = 0);
|
||||
std::vector<PropertyWrapper> all_properties();
|
||||
|
||||
template <typename Type>
|
||||
bool register_property_type() {
|
||||
constexpr auto type = property::impl::type<Type>();
|
||||
return this->register_property_type(type, property::impl::length(type), property::impl::offset(type));
|
||||
constexpr auto type = property::type_from_enum<Type>();
|
||||
return this->register_property_type(type, property::property_count<Type>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool hasProperty(T type) { return this->has(property::impl::type<T>(), type); }
|
||||
bool hasProperty(T type) { return this->has(property::type_from_enum<T>(), type); }
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
PropertyWrapper operator[](T type) {
|
||||
return this->find(property::impl::type<T>(), type);
|
||||
return this->find(property::type_from_enum<T>(), type);
|
||||
}
|
||||
|
||||
PropertyWrapper operator[](const property::PropertyDescription& type) {
|
||||
return this->find(type.type_property, type.property_index);
|
||||
}
|
||||
|
||||
PropertyWrapper operator[](const std::shared_ptr<property::PropertyDescription>& type) {
|
||||
PropertyWrapper operator[](const property::PropertyDescription* type) {
|
||||
return this->find(type->type_property, type->property_index);
|
||||
}
|
||||
|
||||
@ -823,21 +900,21 @@ namespace ts {
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
PropertyWrapper find(T type) {
|
||||
return this->find(property::impl::type<T>(), type);
|
||||
return this->find(property::type_from_enum<T>(), type);
|
||||
}
|
||||
|
||||
PropertyWrapper find(property::PropertyType type, int index);
|
||||
bool has(property::PropertyType type, int index);
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
bool has(T type) { return this->has(property::impl::type<T>(), type); }
|
||||
bool has(T type) { return this->has(property::type_from_enum<T>(), (int) type); }
|
||||
private:
|
||||
bool register_property_type(property::PropertyType /* type */, size_t /* length */, size_t /* offset */);
|
||||
bool register_property_type(property::PropertyType /* type */, size_t /* length */);
|
||||
|
||||
bool save = true;
|
||||
bool save{true};
|
||||
std::vector<std::function<void(PropertyWrapper&)>> notifyFunctions{};
|
||||
|
||||
size_t properties_count = 0;
|
||||
size_t properties_count{0};
|
||||
std::vector<std::shared_ptr<PropertyBundle>> properties;
|
||||
};
|
||||
};
|
||||
|
360
src/PropertyDefinition.h
Normal file
360
src/PropertyDefinition.h
Normal file
@ -0,0 +1,360 @@
|
||||
|
||||
#define FLAG_SS (FLAG_SNAPSHOT | FLAG_SAVE)
|
||||
#define FLAG_SERVER_VV (FLAG_SERVER_VARIABLE | FLAG_SERVER_VIEW)
|
||||
#define FLAG_SERVER_VVSS (FLAG_SERVER_VV | FLAG_SS)
|
||||
|
||||
#define FLAG_CLIENT_VV (FLAG_CLIENT_VARIABLE | FLAG_CLIENT_VIEW)
|
||||
#define FLAG_CLIENT_VVSS (FLAG_CLIENT_VV | FLAG_SS)
|
||||
|
||||
#define V(key, lkey, flags) key, lkey, "0", TYPE_UNSIGNED_NUMBER, flags
|
||||
#define F(key, lkey, flags) key, lkey, "0", TYPE_FLOAT, flags
|
||||
|
||||
#ifdef EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
decltype(property::property_list) property::
|
||||
#else
|
||||
constexpr auto
|
||||
#endif
|
||||
property_list = std::array<PropertyDescription, impl::property_count()>{
|
||||
PropertyDescription{UNKNOWN_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0},
|
||||
|
||||
/* virtual server properties */
|
||||
PropertyDescription{VIRTUALSERVER_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0}, //Must be at index 0!
|
||||
PropertyDescription{VIRTUALSERVER_UNIQUE_IDENTIFIER, "virtualserver_unique_identifier", "", TYPE_STRING, FLAG_SERVER_VV | FLAG_SNAPSHOT},
|
||||
PropertyDescription{VIRTUALSERVER_NAME, "virtualserver_name", "Another TeaSpeak server software user", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE},
|
||||
PropertyDescription{VIRTUALSERVER_WELCOMEMESSAGE, "virtualserver_welcomemessage", "Welcome on another TeaSpeak server. (Download now and a license fee is not your cup of tea! [URL]www.teaspeak.de[/URL])", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE},
|
||||
PropertyDescription{VIRTUALSERVER_PLATFORM, "virtualserver_platform", "undefined", TYPE_STRING, FLAG_SERVER_VIEW},
|
||||
PropertyDescription{VIRTUALSERVER_VERSION, "virtualserver_version", "undefined", TYPE_STRING, FLAG_SERVER_VIEW},
|
||||
PropertyDescription{VIRTUALSERVER_MAXCLIENTS, "virtualserver_maxclients", "120", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE},
|
||||
PropertyDescription{VIRTUALSERVER_PASSWORD, "virtualserver_password", "", TYPE_STRING, FLAG_SS | FLAG_USER_EDITABLE},
|
||||
PropertyDescription{VIRTUALSERVER_CLIENTS_ONLINE, "virtualserver_clientsonline", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE},
|
||||
PropertyDescription{VIRTUALSERVER_QUERYCLIENTS_ONLINE, "virtualserver_queryclientsonline", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_CHANNELS_ONLINE, "virtualserver_channelsonline", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables),
|
||||
PropertyDescription{VIRTUALSERVER_CREATED, "virtualserver_created", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VIEW | FLAG_SS}, //available when connected, stores the time when the server was created
|
||||
PropertyDescription{VIRTUALSERVER_UPTIME, "virtualserver_uptime", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables), the time since the server was started
|
||||
|
||||
PropertyDescription{VIRTUALSERVER_CODEC_ENCRYPTION_MODE, "virtualserver_codec_encryption_mode", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available and always up-to-date when connected
|
||||
PropertyDescription{VIRTUALSERVER_KEYPAIR, "virtualserver_keypair", "", TYPE_STRING, FLAG_SS}, //internal use
|
||||
PropertyDescription{VIRTUALSERVER_HOSTMESSAGE, "virtualserver_hostmessage", "Welcome", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, not updated while connected
|
||||
PropertyDescription{VIRTUALSERVER_HOSTMESSAGE_MODE, "virtualserver_hostmessage_mode", "1", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, not updated while connected
|
||||
PropertyDescription{VIRTUALSERVER_FILEBASE, "virtualserver_filebase", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //not available to clients, stores the folder used for file transfers
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_SERVER_GROUP, "virtualserver_default_server_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //the manager permissions server group that a new manager gets assigned
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_MUSIC_GROUP, "virtualserver_default_music_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //the manager permissions server group that a new manager gets assigned
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_CHANNEL_GROUP, "virtualserver_default_channel_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //the channel permissions group that a new manager gets assigned when joining a channel
|
||||
PropertyDescription{VIRTUALSERVER_FLAG_PASSWORD, "virtualserver_flag_password", "0", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP, "virtualserver_default_channel_admin_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SERVER_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //the channel permissions group that a manager gets assigned when creating a channel
|
||||
PropertyDescription{VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH, "virtualserver_max_download_total_bandwidth", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH, "virtualserver_max_upload_total_bandwidth", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBANNER_URL, "virtualserver_hostbanner_url", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBANNER_GFX_URL, "virtualserver_hostbanner_gfx_url", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBANNER_GFX_INTERVAL, "virtualserver_hostbanner_gfx_interval", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBANNER_MODE, "virtualserver_hostbanner_mode", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_COMPLAIN_AUTOBAN_COUNT, "virtualserver_complain_autoban_count", "5", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_COMPLAIN_AUTOBAN_TIME, "virtualserver_complain_autoban_time", "5", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_COMPLAIN_REMOVE_TIME, "virtualserver_complain_remove_time", "5", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MIN_CLIENTS_IN_CHANNEL_BEFORE_FORCED_SILENCE, "virtualserver_min_clients_in_channel_before_forced_silence", "20", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE},//only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_PRIORITY_SPEAKER_DIMM_MODIFICATOR, "virtualserver_priority_speaker_dimm_modificator", "-18", TYPE_FLOAT, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_ID, "virtualserver_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VIEW}, //available when connected
|
||||
PropertyDescription{VIRTUALSERVER_ANTIFLOOD_POINTS_TICK_REDUCE, "virtualserver_antiflood_points_tick_reduce", "25", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK, "virtualserver_antiflood_points_needed_command_block", "150", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_IP_BLOCK, "virtualserver_antiflood_points_needed_ip_block", "300", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_CLIENT_CONNECTIONS, "virtualserver_client_connections", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_QUERY_CLIENT_CONNECTIONS, "virtualserver_query_client_connections", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBUTTON_TOOLTIP, "virtualserver_hostbutton_tooltip", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBUTTON_URL, "virtualserver_hostbutton_url", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_HOSTBUTTON_GFX_URL, "virtualserver_hostbutton_gfx_url", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_DOWNLOAD_QUOTA, "virtualserver_download_quota", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_UPLOAD_QUOTA, "virtualserver_upload_quota", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MONTH_BYTES_DOWNLOADED, "virtualserver_month_bytes_downloaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MONTH_BYTES_UPLOADED, "virtualserver_month_bytes_uploaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_BYTES_DOWNLOADED, "virtualserver_total_bytes_downloaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_BYTES_UPLOADED, "virtualserver_total_bytes_uploaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SAVE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_PORT, "virtualserver_port", "9987", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_HOST, "virtualserver_host", "0.0.0.0,::", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //internal use | contains comma separated ip list
|
||||
PropertyDescription{VIRTUALSERVER_AUTOSTART, "virtualserver_autostart", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MACHINE_ID, "virtualserver_machine_id", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL, "virtualserver_needed_identity_security_level", "8", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LOG_CLIENT, "virtualserver_log_client", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LOG_QUERY, "virtualserver_log_query", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LOG_CHANNEL, "virtualserver_log_channel", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LOG_PERMISSIONS, "virtualserver_log_permissions", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LOG_SERVER, "virtualserver_log_server", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LOG_FILETRANSFER, "virtualserver_log_filetransfer", "1", TYPE_BOOL, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_NAME_PHONETIC, "virtualserver_name_phonetic", "", TYPE_STRING, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_ICON_ID, "virtualserver_icon_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_RESERVED_SLOTS, "virtualserver_reserved_slots", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_PACKETLOSS_SPEECH, "virtualserver_total_packetloss_speech", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_PACKETLOSS_KEEPALIVE, "virtualserver_total_packetloss_keepalive", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_PACKETLOSS_CONTROL, "virtualserver_total_packetloss_control", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_PACKETLOSS_TOTAL, "virtualserver_total_packetloss_total", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_TOTAL_PING, "virtualserver_total_ping", "0", TYPE_FLOAT, FLAG_SERVER_VARIABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_WEBLIST_ENABLED, "virtualserver_weblist_enabled", "1", TYPE_BOOL, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY, "virtualserver_autogenerated_privilegekey", "", TYPE_STRING, FLAG_SAVE}, //internal use
|
||||
PropertyDescription{VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY, "virtualserver_ask_for_privilegekey", "1", TYPE_BOOL, FLAG_SERVER_VV | FLAG_SAVE | FLAG_USER_EDITABLE}, //available when connected
|
||||
PropertyDescription{VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT, "virtualserver_channel_temp_delete_delay_default", "60", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VVSS | FLAG_USER_EDITABLE}, //available when connected, always up-to-date
|
||||
PropertyDescription{VIRTUALSERVER_MIN_CLIENT_VERSION, "virtualserver_min_client_version", "1445512488", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MIN_ANDROID_VERSION, "virtualserver_min_android_version", "1407159763", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MIN_IOS_VERSION, "virtualserver_min_ios_version", "1407159763", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MIN_WINPHONE_VERSION, "virtualserver_min_winphone_version", "1407159763", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_MAX_CHANNELS, "virtualserver_max_channels", "1000", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
|
||||
PropertyDescription{VIRTUALSERVER_LAST_CLIENT_CONNECT, "virtualserver_last_client_connect", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LAST_QUERY_CONNECT, "virtualserver_last_query_connect", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LAST_CLIENT_DISCONNECT, "virtualserver_last_client_disconnect", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_LAST_QUERY_DISCONNECT, "virtualserver_last_query_disconnect", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS}, //only available on request (=> requestServerVariables)
|
||||
|
||||
PropertyDescription{VIRTUALSERVER_WEB_HOST, "virtualserver_web_host", "0.0.0.0", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_WEB_PORT, "virtualserver_web_port", "0", TYPE_UNSIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_CLIENT_DESCRIPTION, "virtualserver_default_client_description", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_CHANNEL_DESCRIPTION, "virtualserver_default_channel_description", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_DEFAULT_CHANNEL_TOPIC, "virtualserver_default_channel_topic", "", TYPE_STRING, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
|
||||
PropertyDescription{VIRTUALSERVER_MUSIC_BOT_LIMIT, "virtualserver_music_bot_limit", "-1", TYPE_SIGNED_NUMBER, FLAG_SERVER_VARIABLE | FLAG_NEW | FLAG_SS | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_SPOKEN_TIME, "virtualserver_spoken_time", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_NEW | FLAG_SAVE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_DISABLE_IP_SAVING, "virtualserver_disable_ip_saving", "0", TYPE_BOOL, FLAG_INTERNAL | FLAG_NEW | FLAG_SAVE | FLAG_USER_EDITABLE}, //only available on request (=> requestServerVariables)
|
||||
PropertyDescription{VIRTUALSERVER_COUNTRY_CODE, "virtualserver_country_code", "XX", TYPE_STRING, FLAG_SERVER_VV | FLAG_SAVE | FLAG_USER_EDITABLE}, //available when connected
|
||||
|
||||
/* channel properties */
|
||||
PropertyDescription{CHANNEL_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0}, //Must be at index 0!
|
||||
PropertyDescription{CHANNEL_ID, "cid", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS},
|
||||
PropertyDescription{CHANNEL_PID, "cpid", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS},
|
||||
PropertyDescription{CHANNEL_NAME, "channel_name", "undefined", TYPE_STRING, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_TOPIC, "channel_topic", "", TYPE_STRING, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_DESCRIPTION, "channel_description", "", TYPE_STRING, FLAG_CHANNEL_VARIABLE | FLAG_SS | FLAG_USER_EDITABLE}, //Must be requested (=> requestChannelDescription)
|
||||
PropertyDescription{CHANNEL_PASSWORD, "channel_password", "0", TYPE_STRING, FLAG_SS | FLAG_USER_EDITABLE}, //not available manager side
|
||||
PropertyDescription{CHANNEL_CODEC, "channel_codec", "4", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_CODEC_QUALITY, "channel_codec_quality", "7", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_MAXCLIENTS, "channel_maxclients", "-1", TYPE_SIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_MAXFAMILYCLIENTS, "channel_maxfamilyclients", "-1", TYPE_SIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_ORDER, "channel_order", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_PERMANENT, "channel_flag_permanent", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_SEMI_PERMANENT, "channel_flag_semi_permanent", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_DEFAULT, "channel_flag_default", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_PASSWORD, "channel_flag_password", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_CODEC_LATENCY_FACTOR, "channel_codec_latency_factor", "1", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_CODEC_IS_UNENCRYPTED, "channel_codec_is_unencrypted", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_SECURITY_SALT, "channel_security_salt", "", TYPE_STRING, FLAG_SS}, //Not available manager side, not used in teamspeak, only SDK. Sets the options+salt for security hash.
|
||||
PropertyDescription{CHANNEL_DELETE_DELAY, "channel_delete_delay", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //How many seconds to wait before deleting this channel
|
||||
PropertyDescription{CHANNEL_FLAG_MAXCLIENTS_UNLIMITED, "channel_flag_maxclients_unlimited", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED, "channel_flag_maxfamilyclients_unlimited", "1", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE},//Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED, "channel_flag_maxfamilyclients_inherited", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE},//Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_ARE_SUBSCRIBED, "channel_flag_are_subscribed", "1", TYPE_BOOL, FLAG_INTERNAL}, //Only available manager side, stores whether we are subscribed to this channel
|
||||
PropertyDescription{CHANNEL_FILEPATH, "channel_filepath", "", TYPE_STRING, FLAG_SS}, //not available manager side, the folder used for file-transfers for this channel
|
||||
PropertyDescription{CHANNEL_NEEDED_TALK_POWER, "channel_needed_talk_power", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FORCED_SILENCE, "channel_forced_silence", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_NAME_PHONETIC, "channel_name_phonetic", "", TYPE_STRING, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_ICON_ID, "channel_icon_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_CHANNEL_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_FLAG_PRIVATE, "channel_flag_private", "0", TYPE_BOOL, FLAG_CHANNEL_VIEW | FLAG_SS}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_LAST_LEFT, "channel_last_left", "0", TYPE_UNSIGNED_NUMBER, FLAG_SAVE | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_CREATED_AT, "channel_created_at", "0", TYPE_UNSIGNED_NUMBER, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_CREATED_BY, "channel_created_by", "0", TYPE_UNSIGNED_NUMBER, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW}, //Available for all channels that are "in view", always up-to-date
|
||||
PropertyDescription{CHANNEL_CONVERSATION_HISTORY_LENGTH, "channel_conversation_history_length", "1500", TYPE_SIGNED_NUMBER, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW | FLAG_USER_EDITABLE},
|
||||
PropertyDescription{CHANNEL_FLAG_CONVERSATION_PRIVATE, "channel_flag_conversation_private", "0", TYPE_BOOL, FLAG_SS | FLAG_CHANNEL_VIEW | FLAG_CHANNEL_VARIABLE | FLAG_NEW | FLAG_USER_EDITABLE},
|
||||
|
||||
/* group properties, this may gets removed */
|
||||
PropertyDescription{GROUP_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0},
|
||||
PropertyDescription{GROUP_ID, "gid", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL},
|
||||
PropertyDescription{GROUP_TYPE, "type", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW},
|
||||
PropertyDescription{GROUP_NAME, "name", "Undefined group", TYPE_STRING, FLAG_GROUP_VIEW},
|
||||
PropertyDescription{GROUP_SORTID, "sortid", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW},
|
||||
PropertyDescription{GROUP_SAVEDB, "savedb", "0", TYPE_BOOL, FLAG_GROUP_VIEW},
|
||||
PropertyDescription{GROUP_NAMEMODE, "namemode", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW},
|
||||
PropertyDescription{GROUP_ICONID, "iconid", "0", TYPE_UNSIGNED_NUMBER, FLAG_GROUP_VIEW},
|
||||
|
||||
/* client properties */
|
||||
PropertyDescription{CLIENT_UNDEFINED, "undefined", "undefined", TYPE_UNKNOWN, 0},
|
||||
PropertyDescription{CLIENT_UNIQUE_IDENTIFIER, "client_unique_identifier", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SNAPSHOT | FLAG_GLOBAL}, //automatically up-to-date for any manager "in view", can be used to identify this particular manager installation
|
||||
PropertyDescription{CLIENT_NICKNAME, "client_nickname", "undefined", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SAVE_MUSIC | FLAG_SNAPSHOT | FLAG_GLOBAL | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_VERSION, "client_version", "unknown", TYPE_STRING, FLAG_CLIENT_VVSS | FLAG_USER_EDITABLE | FLAG_GLOBAL | FLAG_SAVE_MUSIC}, //for other clients than ourself, this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_PLATFORM, "client_platform", "unknown", TYPE_STRING, FLAG_CLIENT_VVSS | FLAG_USER_EDITABLE | FLAG_GLOBAL | FLAG_SAVE_MUSIC}, //for other clients than ourself, this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_FLAG_TALKING, "client_flag_talking", "0", TYPE_BOOL, FLAG_INTERNAL}, //automatically up-to-date for any manager that can be heard (in room / whisper)
|
||||
PropertyDescription{CLIENT_INPUT_MUTED, "client_input_muted", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients microphone mute status
|
||||
PropertyDescription{CLIENT_OUTPUT_MUTED, "client_output_muted", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients headphones/speakers/mic combined mute status
|
||||
PropertyDescription{CLIENT_OUTPUTONLY_MUTED, "client_outputonly_muted", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients headphones/speakers only mute status
|
||||
PropertyDescription{CLIENT_INPUT_HARDWARE, "client_input_hardware", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients microphone hardware status (is the capture device opened?)
|
||||
PropertyDescription{CLIENT_OUTPUT_HARDWARE, "client_output_hardware", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients headphone/speakers hardware status (is the playback device opened?)
|
||||
PropertyDescription{CLIENT_DEFAULT_CHANNEL, "client_default_channel", "", TYPE_STRING, FLAG_INTERNAL}, //only usable for ourself, the default channel we used to connect on our last connection attempt
|
||||
PropertyDescription{CLIENT_DEFAULT_CHANNEL_PASSWORD, "client_default_channel_password", "", TYPE_STRING, FLAG_INTERNAL}, //internal use
|
||||
PropertyDescription{CLIENT_SERVER_PASSWORD, "client_server_password", "", TYPE_STRING, FLAG_INTERNAL}, //internal use
|
||||
PropertyDescription{CLIENT_META_DATA, "client_meta_data", "", TYPE_STRING, FLAG_CLIENT_VIEW| FLAG_GLOBAL|FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", not used by TeamSpeak, free storage for sdk users
|
||||
PropertyDescription{CLIENT_IS_RECORDING, "client_is_recording", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_VERSION_SIGN, "client_version_sign", "", TYPE_STRING, FLAG_INTERNAL}, //sign
|
||||
PropertyDescription{CLIENT_SECURITY_HASH, "client_security_hash", "", TYPE_STRING, FLAG_INTERNAL}, //SDK use, not used by teamspeak. Hash is provided by an outside source. A channel will use the security salt + other manager data to calculate a hash, which must be the same as the one provided here.
|
||||
|
||||
//Rare properties
|
||||
PropertyDescription{CLIENT_KEY_OFFSET, "client_key_offset", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL}, //internal use
|
||||
PropertyDescription{CLIENT_LOGIN_NAME, "client_login_name", "", TYPE_STRING, FLAG_CLIENT_VARIABLE| FLAG_GLOBAL}, //used for serverquery clients, makes no sense on normal clients currently
|
||||
PropertyDescription{CLIENT_LOGIN_PASSWORD, "client_login_password", "", TYPE_STRING, FLAG_INTERNAL| FLAG_GLOBAL}, //used for serverquery clients, makes no sense on normal clients currently
|
||||
PropertyDescription{CLIENT_DATABASE_ID, "client_database_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_GLOBAL}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds database manager id
|
||||
PropertyDescription{CLIENT_ID, "clid", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VV}, //clid!
|
||||
PropertyDescription{CLIENT_HARDWARE_ID, "hwid", "", TYPE_STRING, FLAG_SAVE}, //hwid!
|
||||
PropertyDescription{CLIENT_CHANNEL_GROUP_ID, "client_channel_group_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds database manager id
|
||||
PropertyDescription{CLIENT_SERVERGROUPS, "client_servergroups", "0", TYPE_STRING, FLAG_CLIENT_VIEW}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds all servergroups manager belongs too
|
||||
PropertyDescription{CLIENT_CREATED, "client_created", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE_MUSIC | FLAG_SNAPSHOT | FLAG_GLOBAL}, //this needs to be requested (=> requestClientVariables), first time this manager connected to this server
|
||||
PropertyDescription{CLIENT_LASTCONNECTED, "client_lastconnected", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SNAPSHOT | FLAG_GLOBAL}, //this needs to be requested (=> requestClientVariables), last time this manager connected to this server
|
||||
PropertyDescription{CLIENT_TOTALCONNECTIONS, "client_totalconnections", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_CLIENT_VIEW | FLAG_SNAPSHOT | FLAG_GLOBAL}, //this needs to be requested (=> requestClientVariables), how many times this manager connected to this server
|
||||
PropertyDescription{CLIENT_AWAY, "client_away", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients away status
|
||||
PropertyDescription{CLIENT_AWAY_MESSAGE, "client_away_message", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this clients away message
|
||||
PropertyDescription{CLIENT_TYPE, "client_type", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_GLOBAL}, //automatically up-to-date for any manager "in view", determines if this is a real manager or a server-query connection
|
||||
PropertyDescription{CLIENT_TYPE_EXACT, "client_type_exact", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_NEW | FLAG_GLOBAL}, //automatically up-to-date for any manager "in view", determines if this is a real manager or a server-query connection
|
||||
PropertyDescription{CLIENT_FLAG_AVATAR, "client_flag_avatar", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SAVE | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", this manager got an avatar
|
||||
PropertyDescription{CLIENT_TALK_POWER, "client_talk_power", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds database manager id
|
||||
PropertyDescription{CLIENT_TALK_REQUEST, "client_talk_request", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds timestamp where manager requested to talk
|
||||
PropertyDescription{CLIENT_TALK_REQUEST_MSG, "client_talk_request_msg", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, holds matter for the request
|
||||
PropertyDescription{CLIENT_DESCRIPTION, "client_description", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_IS_TALKER, "client_is_talker", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_MONTH_BYTES_UPLOADED, "client_month_bytes_uploaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE}, //this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_MONTH_BYTES_DOWNLOADED, "client_month_bytes_downloaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE}, //this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_TOTAL_BYTES_UPLOADED, "client_total_bytes_uploaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE}, //this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_TOTAL_BYTES_DOWNLOADED, "client_total_bytes_downloaded", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE}, //this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_TOTAL_ONLINE_TIME, "client_total_online_time", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE | FLAG_NEW}, //this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_MONTH_ONLINE_TIME, "client_month_online_time", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VARIABLE | FLAG_SAVE | FLAG_NEW}, //this needs to be requested (=> requestClientVariables)
|
||||
PropertyDescription{CLIENT_IS_PRIORITY_SPEAKER, "client_is_priority_speaker", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_UNREAD_MESSAGES, "client_unread_messages", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_NICKNAME_PHONETIC, "client_nickname_phonetic", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_NEEDED_SERVERQUERY_VIEW_POWER, "client_needed_serverquery_view_power", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_DEFAULT_TOKEN, "client_default_token", "", TYPE_STRING, FLAG_INTERNAL}, //only usable for ourself, the default token we used to connect on our last connection attempt
|
||||
PropertyDescription{CLIENT_ICON_ID, "client_icon_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW | FLAG_CLIENT_VARIABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_IS_CHANNEL_COMMANDER, "client_is_channel_commander", "0", TYPE_BOOL, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE | FLAG_SAVE_MUSIC}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_COUNTRY, "client_country", "TS", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_CLIENT_VARIABLE | FLAG_GLOBAL | FLAG_SAVE_MUSIC | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view"
|
||||
PropertyDescription{CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID, "client_channel_group_inherited_channel_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_CLIENT_VIEW}, //automatically up-to-date for any manager "in view", only valid with PERMISSION feature, contains channel_id where the channel_group_id is set from
|
||||
PropertyDescription{CLIENT_BADGES, "client_badges", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", stores icons for partner badges
|
||||
PropertyDescription{CLIENT_MYTEAMSPEAK_ID, "client_myteamspeak_id", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_SS | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", stores icons for partner badges
|
||||
PropertyDescription{CLIENT_INTEGRATIONS, "client_integrations", "", TYPE_STRING, FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE}, //automatically up-to-date for any manager "in view", stores icons for partner badges
|
||||
PropertyDescription{CLIENT_ACTIVE_INTEGRATIONS_INFO, "client_active_integrations_info", "", TYPE_STRING, FLAG_INTERNAL | FLAG_USER_EDITABLE},
|
||||
|
||||
//Using FLAG_GLOBAL here,lse they will be overridden on clientinit
|
||||
PropertyDescription{CLIENT_TEAFORO_ID, "client_teaforo_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_GLOBAL},
|
||||
PropertyDescription{CLIENT_TEAFORO_NAME, "client_teaforo_name", "", TYPE_STRING, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_GLOBAL},
|
||||
PropertyDescription{CLIENT_TEAFORO_FLAGS, "client_teaforo_flags", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_GLOBAL},
|
||||
|
||||
//Music bot stuff
|
||||
PropertyDescription{CLIENT_OWNER, "client_owner", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW},
|
||||
PropertyDescription{CLIENT_BOT_TYPE, "client_bot_type", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_SAVE_MUSIC | FLAG_USER_EDITABLE | FLAG_CLIENT_VIEW},
|
||||
PropertyDescription{CLIENT_LAST_CHANNEL, "client_last_channel", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_INTERNAL | FLAG_SAVE_MUSIC},
|
||||
PropertyDescription{CLIENT_PLAYER_STATE, "player_state", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VIEW | FLAG_SAVE_MUSIC},
|
||||
PropertyDescription{CLIENT_PLAYER_VOLUME, "player_volume", "1", TYPE_FLOAT, FLAG_NEW | FLAG_SAVE_MUSIC | FLAG_CLIENT_VIEW | FLAG_USER_EDITABLE},
|
||||
PropertyDescription{CLIENT_PLAYLIST_ID, "client_playlist_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VARIABLE | FLAG_SAVE_MUSIC},
|
||||
PropertyDescription{CLIENT_DISABLED, "client_disabled", "0", TYPE_BOOL, FLAG_NEW | FLAG_CLIENT_VARIABLE},
|
||||
PropertyDescription{CLIENT_UPTIME_MODE, "client_uptime_mode", "0", TYPE_UNSIGNED_NUMBER, FLAG_NEW | FLAG_CLIENT_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE_MUSIC},
|
||||
PropertyDescription{CLIENT_FLAG_NOTIFY_SONG_CHANGE, "client_flag_notify_song_change", "1", TYPE_BOOL, FLAG_NEW | FLAG_CLIENT_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE_MUSIC},
|
||||
|
||||
/* connection list properties */
|
||||
PropertyDescription{CONNECTION_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0},
|
||||
PropertyDescription{CONNECTION_PING, "connection_ping", "0", TYPE_UNSIGNED_NUMBER, 0}, //average latency for a round trip through and back this connection
|
||||
PropertyDescription{CONNECTION_PING_DEVIATION, "connection_ping_deviation", "0", TYPE_UNSIGNED_NUMBER, 0}, //standard deviation of the above average latency
|
||||
PropertyDescription{CONNECTION_CONNECTED_TIME, "connection_connected_time", "0", TYPE_UNSIGNED_NUMBER, 0}, //how long the connection exists already
|
||||
PropertyDescription{CONNECTION_IDLE_TIME, "connection_idle_time", "0", TYPE_UNSIGNED_NUMBER, 0}, //how long since the last action of this manager
|
||||
PropertyDescription{CONNECTION_CLIENT_IP, "connection_client_ip", "", TYPE_STRING, FLAG_SAVE}, //NEED DB SAVE! //IP of this manager (as seen from the server side)
|
||||
PropertyDescription{CONNECTION_CLIENT_PORT, "connection_client_port", "0", TYPE_UNSIGNED_NUMBER, 0}, //Port of this manager (as seen from the server side)
|
||||
PropertyDescription{CONNECTION_SERVER_IP, "connection_server_ip", "", TYPE_STRING, 0}, //IP of the server (seen from the manager side) - only available on yourself, not for remote clients, not available server side
|
||||
PropertyDescription{CONNECTION_SERVER_PORT, "connection_server_port", "0", TYPE_UNSIGNED_NUMBER, 0}, //Port of the server (seen from the manager side) - only available on yourself, not for remote clients, not available server side
|
||||
|
||||
PropertyDescription{V(CONNECTION_PACKETS_SENT_SPEECH, "connection_packets_sent_speech", 0)}, //how many Speech packets were sent through this connection
|
||||
PropertyDescription{V(CONNECTION_PACKETS_SENT_KEEPALIVE, "connection_packets_sent_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_PACKETS_SENT_CONTROL, "connection_packets_sent_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_PACKETS_SENT_TOTAL, "connection_packets_sent_total", FLAG_CLIENT_INFO)}, //how many packets were sent totally (this is PACKETS_SENT_SPEECH + PACKETS_SENT_KEEPALIVE + PACKETS_SENT_CONTROL)
|
||||
PropertyDescription{V(CONNECTION_BYTES_SENT_SPEECH, "connection_bytes_sent_speech", 0)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_SENT_KEEPALIVE, "connection_bytes_sent_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_SENT_CONTROL, "connection_bytes_sent_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_SENT_TOTAL, "connection_bytes_sent_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{V(CONNECTION_PACKETS_RECEIVED_SPEECH, "connection_packets_received_speech", 0)},
|
||||
PropertyDescription{V(CONNECTION_PACKETS_RECEIVED_KEEPALIVE, "connection_packets_received_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_PACKETS_RECEIVED_CONTROL, "connection_packets_received_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_PACKETS_RECEIVED_TOTAL, "connection_packets_received_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_RECEIVED_SPEECH, "connection_bytes_received_speech", 0)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_RECEIVED_KEEPALIVE, "connection_bytes_received_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_RECEIVED_CONTROL, "connection_bytes_received_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_BYTES_RECEIVED_TOTAL, "connection_bytes_received_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{F(CONNECTION_PACKETLOSS_SPEECH, "connection_packetloss_speech", 0)},
|
||||
PropertyDescription{F(CONNECTION_PACKETLOSS_KEEPALIVE, "connection_packetloss_keepalive", 0)},
|
||||
PropertyDescription{F(CONNECTION_PACKETLOSS_CONTROL, "connection_packetloss_control", 0)},
|
||||
PropertyDescription{F(CONNECTION_PACKETLOSS_TOTAL, "connection_packetloss_total", FLAG_CLIENT_INFO)}, //the probability with which a packet round trip failed because a packet was lost
|
||||
PropertyDescription{F(CONNECTION_SERVER2CLIENT_PACKETLOSS_SPEECH, "connection_server2client_packetloss_speech", 0)}, //the probability with which a speech packet failed from the server to the manager
|
||||
PropertyDescription{F(CONNECTION_SERVER2CLIENT_PACKETLOSS_KEEPALIVE, "connection_server2client_packetloss_keepalive", 0)},
|
||||
PropertyDescription{F(CONNECTION_SERVER2CLIENT_PACKETLOSS_CONTROL, "connection_server2client_packetloss_control", 0)},
|
||||
PropertyDescription{F(CONNECTION_SERVER2CLIENT_PACKETLOSS_TOTAL, "connection_server2client_packetloss_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{F(CONNECTION_CLIENT2SERVER_PACKETLOSS_SPEECH, "connection_client2server_packetloss_speech", 0)},
|
||||
PropertyDescription{F(CONNECTION_CLIENT2SERVER_PACKETLOSS_KEEPALIVE, "connection_client2server_packetloss_keepalive", 0)},
|
||||
PropertyDescription{F(CONNECTION_CLIENT2SERVER_PACKETLOSS_CONTROL, "connection_client2server_packetloss_control", 0)},
|
||||
PropertyDescription{F(CONNECTION_CLIENT2SERVER_PACKETLOSS_TOTAL, "connection_client2server_packetloss_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_SPEECH, "connection_bandwidth_sent_last_second_speech", 0)}, //howmany bytes of speech packets we sent during the last second
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_KEEPALIVE, "connection_bandwidth_sent_last_second_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_CONTROL, "connection_bandwidth_sent_last_second_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_SECOND_TOTAL, "connection_bandwidth_sent_last_second_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_SPEECH, "connection_bandwidth_sent_last_minute_speech", 0)}, //howmany bytes/s of speech packets we sent in average during the last minute
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_KEEPALIVE, "connection_bandwidth_sent_last_minute_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_CONTROL, "connection_bandwidth_sent_last_minute_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_TOTAL, "connection_bandwidth_sent_last_minute_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_SPEECH, "connection_bandwidth_received_last_second_speech", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_KEEPALIVE, "connection_bandwidth_received_last_second_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_CONTROL, "connection_bandwidth_received_last_second_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_TOTAL, "connection_bandwidth_received_last_second_total", FLAG_CLIENT_INFO)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_SPEECH, "connection_bandwidth_received_last_minute_speech", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_KEEPALIVE, "connection_bandwidth_received_last_minute_keepalive", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_CONTROL, "connection_bandwidth_received_last_minute_control", 0)},
|
||||
PropertyDescription{V(CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_TOTAL, "connection_bandwidth_received_last_minute_total", FLAG_CLIENT_INFO)},
|
||||
|
||||
//Rare properties
|
||||
PropertyDescription{V(CONNECTION_FILETRANSFER_BANDWIDTH_SENT, "connection_filetransfer_bandwidth_sent", FLAG_CLIENT_INFO)}, //how many bytes per second are currently being sent by file transfers
|
||||
PropertyDescription{V(CONNECTION_FILETRANSFER_BANDWIDTH_RECEIVED, "connection_filetransfer_bandwidth_received", FLAG_CLIENT_INFO)}, //how many bytes per second are currently being received by file transfers
|
||||
PropertyDescription{V(CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL, "connection_filetransfer_bytes_received_total", FLAG_CLIENT_INFO)}, //how many bytes we received in total through file transfers
|
||||
PropertyDescription{V(CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL, "connection_filetransfer_bytes_sent_total", FLAG_CLIENT_INFO)}, //how many bytes we sent in total through file transfers
|
||||
|
||||
/* server instance properties */
|
||||
PropertyDescription{SERVERINSTANCE_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0},
|
||||
PropertyDescription{SERVERINSTANCE_DATABASE_VERSION, "serverinstance_database_version", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE},
|
||||
PropertyDescription{SERVERINSTANCE_PERMISSIONS_VERSION, "serverinstance_permissions_version", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE},
|
||||
PropertyDescription{SERVERINSTANCE_FILETRANSFER_HOST, "serverinstance_filetransfer_host", "0.0.0.0,[::]", TYPE_STRING, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_FILETRANSFER_PORT, "serverinstance_filetransfer_port", "30303", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_FILETRANSFER_MAX_CONNECTIONS, "serverinstance_filetransfer_max_connections", "100", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_FILETRANSFER_MAX_CONNECTIONS_PER_IP, "serverinstance_filetransfer_max_connections_per_ip", "20", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_QUERY_HOST, "serverinstance_query_host", "0.0.0.0,[::]", TYPE_STRING, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_QUERY_PORT, "serverinstance_query_port", "10101", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_QUERY_MAX_CONNECTIONS, "serverinstance_query_max_connections", "100", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_QUERY_MAX_CONNECTIONS_PER_IP, "serverinstance_query_max_connections_per_ip", "3", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_MONTHLY_TIMESTAMP, "serverinstance_monthly_timestamp", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_MAX_DOWNLOAD_TOTAL_BANDWIDTH, "serverinstance_max_download_total_bandwidth", "-1", TYPE_SIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_MAX_UPLOAD_TOTAL_BANDWIDTH, "serverinstance_max_upload_total_bandwidth", "-1", TYPE_SIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_SERVERQUERY_FLOOD_COMMANDS, "serverinstance_serverquery_flood_commands", "3", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE}, //how many commands we can issue while in the SERVERINSTANCE_SERVERQUERY_FLOOD_TIME window
|
||||
PropertyDescription{SERVERINSTANCE_SERVERQUERY_FLOOD_TIME, "serverinstance_serverquery_flood_time", "1", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE}, //time window in seconds for max command execution check
|
||||
PropertyDescription{SERVERINSTANCE_SERVERQUERY_BAN_TIME, "serverinstance_serverquery_ban_time", "600", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE}, //how many seconds someone get banned if he floods
|
||||
PropertyDescription{SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP, "serverinstance_template_serveradmin_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP, "serverinstance_template_serverdefault_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP, "serverinstance_template_channeladmin_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP, "serverinstance_template_channeldefault_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP, "serverinstance_template_musicdefault_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_GUEST_SERVERQUERY_GROUP, "serverinstance_guest_serverquery_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP, "serverinstance_admin_serverquery_group", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_PENDING_CONNECTIONS_PER_IP, "serverinstance_pending_connections_per_ip", "0", TYPE_UNSIGNED_NUMBER, FLAG_INSTANCE_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{SERVERINSTANCE_SPOKEN_TIME_TOTAL, "serverinstance_spoken_time_total", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW},
|
||||
PropertyDescription{SERVERINSTANCE_SPOKEN_TIME_DELETED, "serverinstance_spoken_time_deleted", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW},
|
||||
PropertyDescription{SERVERINSTANCE_SPOKEN_TIME_ALIVE, "serverinstance_spoken_time_alive", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW},
|
||||
PropertyDescription{SERVERINSTANCE_SPOKEN_TIME_VARIANZ, "serverinstance_spoken_time_varianz", "0", TYPE_UNSIGNED_NUMBER, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW},
|
||||
PropertyDescription{SERVERINSTANCE_VIRTUAL_SERVER_ID_INDEX, "serverinstance_virtual_server_id_index", "1", TYPE_UNSIGNED_NUMBER, FLAG_SAVE | FLAG_INSTANCE_VARIABLE | FLAG_NEW},
|
||||
PropertyDescription{SERVERINSTANCE_UNIQUE_ID, "serverinstance_unique_id", "", TYPE_STRING, FLAG_INTERNAL | FLAG_SAVE | FLAG_NEW},
|
||||
|
||||
/* playlist properties */
|
||||
PropertyDescription{PLAYLIST_UNDEFINED, "undefined", "", TYPE_UNKNOWN, 0},
|
||||
PropertyDescription{PLAYLIST_ID, "playlist_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE},
|
||||
PropertyDescription{PLAYLIST_TITLE, "playlist_title", "Yet another playlist", TYPE_STRING, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_DESCRIPTION, "playlist_description", "", TYPE_STRING, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_TYPE, "playlist_type", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_OWNER_DBID, "playlist_owner_dbid", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_OWNER_NAME, "playlist_owner_name", "0", TYPE_STRING, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_MAX_SONGS, "playlist_max_songs", "-1", TYPE_SIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_FLAG_DELETE_PLAYED, "playlist_flag_delete_played", "1", TYPE_BOOL, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_FLAG_FINISHED, "playlist_flag_finished", "0", TYPE_BOOL, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_REPLAY_MODE, "playlist_replay_mode", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_USER_EDITABLE | FLAG_SAVE},
|
||||
PropertyDescription{PLAYLIST_CURRENT_SONG_ID, "playlist_current_song_id", "0", TYPE_UNSIGNED_NUMBER, FLAG_PLAYLIST_VARIABLE | FLAG_SAVE}
|
||||
};
|
||||
|
||||
#undef str_
|
||||
#undef V
|
||||
#undef F
|
||||
|
||||
#undef FLAG_SS
|
||||
#undef FLAG_SERVER_VV
|
||||
#undef FLAG_SERVER_VVSS
|
||||
#undef FLAG_CLIENT_VV
|
||||
#undef FLAG_CLIENT_VVSS
|
84
src/PropertyDefinitions.cpp
Normal file
84
src/PropertyDefinitions.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
//
|
||||
// Created by WolverinDEV on 08/04/2020.
|
||||
//
|
||||
|
||||
#include "./Properties.h"
|
||||
|
||||
using namespace ts;
|
||||
|
||||
#ifdef EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
using PropertyDescription = property::PropertyDescription;
|
||||
#include "./PropertyDefinition.h"
|
||||
const property::PropertyListInfo property::property_list_info = impl::list_info();
|
||||
#endif
|
||||
|
||||
using PropertyType = property::PropertyType;
|
||||
using PropertyType = property::PropertyType;
|
||||
|
||||
/* verifier methods */
|
||||
constexpr bool validate_property_list_contains_all_types() {
|
||||
for(const auto& entry : property::property_list_info.begin_index)
|
||||
if(entry >= property::property_list.size())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool validate_all_names_valid() {
|
||||
for(const auto& entry : property::property_list)
|
||||
for(const auto& c : entry.name)
|
||||
if(!((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool validate_first_property_undefined() {
|
||||
for(const auto& index : property::property_list_info.begin_index)
|
||||
if(index < property::property_list.size())
|
||||
if(property::property_list[index].name != "undefined")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool property_list_ordered() {
|
||||
static_assert(!property::property_list.empty());
|
||||
|
||||
/* initial setup */
|
||||
std::array<bool, PropertyType::PROP_TYPE_MAX> visited_types{};
|
||||
PropertyType current_type{property::property_list[0].type_property};
|
||||
visited_types[current_type] = true;
|
||||
size_t last_id{(size_t) property::property_list[0].property_index};
|
||||
if(last_id != 0) return false;
|
||||
|
||||
/* iterate */
|
||||
for(auto index{1}; index < property::property_list.size(); index++) {
|
||||
const auto& entry = property::property_list[index];
|
||||
if(last_id + 1 != entry.property_index) {
|
||||
if(current_type == entry.type_property)
|
||||
return false;
|
||||
if(visited_types[entry.type_property])
|
||||
return false;
|
||||
if(entry.property_index != 0) /* new type must start with 0 (undefined) */
|
||||
return false;
|
||||
visited_types[current_type = entry.type_property] = true;
|
||||
last_id = 0;
|
||||
} else if(current_type != entry.type_property)
|
||||
return false;
|
||||
else
|
||||
last_id++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef EXTERNALIZE_PROPERTY_DEFINITIONS
|
||||
__attribute__((constructor)) void validate_properties() {
|
||||
assert(property_list_ordered());
|
||||
assert(validate_first_property_undefined());
|
||||
assert(validate_property_list_contains_all_types());
|
||||
assert(validate_all_names_valid());
|
||||
}
|
||||
#else
|
||||
static_assert(property_list_ordered(), "Property list is unordered!");
|
||||
static_assert(validate_first_property_undefined(), "First property of each type must be the undefined property");
|
||||
static_assert(validate_property_list_contains_all_types(), "Missing property begin for a property type");
|
||||
static_assert(validate_all_names_valid(), "Property list contains name which does not match the expected names: [a-z_]+");
|
||||
#endif
|
@ -58,8 +58,10 @@ class variable {
|
||||
variable& operator=(const variable& ref);
|
||||
variable& operator=(variable&& ref);
|
||||
|
||||
std::string key() const { return data->pair.first; }
|
||||
std::string value() const { return data->pair.second; }
|
||||
[[nodiscard]] std::string key() const { return this->r_key(); }
|
||||
void set_key(const std::string_view& key) const { this->r_key() = key; }
|
||||
|
||||
std::string value() const { return this->r_value(); }
|
||||
VariableType type() const { return data->_type; }
|
||||
variable clone(){ return variable(key(), value(), type()); }
|
||||
|
||||
@ -68,7 +70,13 @@ class variable {
|
||||
variable&operator=(std::nullptr_t) { r_value() = ""; data->_type = VARTYPE_NULL; return *this;}
|
||||
|
||||
template <typename T>
|
||||
T as() const { return typecast::variable_cast<T>(*this); }
|
||||
T as() const {
|
||||
try {
|
||||
return typecast::variable_cast<T>(*this);
|
||||
} catch(std::exception& ex) {
|
||||
throw std::invalid_argument{"failed to parse " + this->r_key() + " as " + typeid(T).name() + " (" + ex.what() + ")"};
|
||||
}
|
||||
}
|
||||
std::string string() const { return as<std::string>(); } //fast
|
||||
|
||||
template <typename T> //TODO more secure and not just try and fail
|
||||
@ -123,6 +131,7 @@ DEFINE_VARIABLE_TRANSFORM_TYPE(type, ntype)
|
||||
DEFINE_VARIABLE_TRANSFORM(class, VARTYPE_INT, std::to_string((size_type) in), static_cast<class>(in.as<size_type>()));
|
||||
|
||||
DEFINE_VARIABLE_TRANSFORM(std::string, VARTYPE_TEXT, in, in.value());
|
||||
DEFINE_VARIABLE_TRANSFORM(std::string_view, VARTYPE_TEXT, std::string{in}, std::string_view{in});
|
||||
DEFINE_VARIABLE_TRANSFORM(char*, VARTYPE_TEXT, std::string((const char*) in), (char*) in.value().c_str());
|
||||
DEFINE_VARIABLE_TRANSFORM(const char*, VARTYPE_TEXT, std::string((const char*) in), in.value().c_str());
|
||||
|
||||
|
@ -37,4 +37,5 @@ CONVERTER_PRIMITIVE_ST(double, std::stod(std::string{str}));
|
||||
CONVERTER_PRIMITIVE_ST(long_double, std::stold(std::string{str}));
|
||||
|
||||
CONVERTER_ST(std__string, return std::string{str};, return std::any_cast<std__string>(value););
|
||||
CONVERTER_ST(const_char__ , return str.data();, return std::string(std::any_cast<const_char__>(value)););
|
||||
CONVERTER_ST(std__string_view, return str;, return std::string{std::any_cast<std__string_view>(value)};);
|
||||
CONVERTER_ST(const_char__ , return str.data();, return std::string{std::any_cast<const_char__>(value)};);
|
@ -54,8 +54,10 @@ namespace ts {
|
||||
CONVERTER_PRIMITIVE(uint64_t);
|
||||
|
||||
typedef std::string std__string;
|
||||
typedef std::string_view std__string_view;
|
||||
typedef const char* const_char__;
|
||||
CONVERTER_PRIMITIVE(std__string);
|
||||
CONVERTER_PRIMITIVE(std__string_view);
|
||||
CONVERTER_PRIMITIVE(const_char__);
|
||||
|
||||
/* const expr char literal */
|
||||
|
@ -5,7 +5,7 @@
|
||||
std::string base64::decode(const char* input, size_t size) {
|
||||
auto out = new unsigned char[size];
|
||||
if(base64_strict_decode((unsigned char*) input, (unsigned long) size, out, (unsigned long*) &size) != CRYPT_OK){
|
||||
std::cerr << "Invalid base 64 string '" << input << "'" << std::endl;
|
||||
//std::cerr << "Invalid base 64 string '" << input << "'" << std::endl;
|
||||
return "";
|
||||
}
|
||||
std::string ret((char*) out, size);
|
||||
@ -17,7 +17,7 @@ std::string base64::encode(const char* input, const unsigned long inputSize) {
|
||||
auto outlen = static_cast<unsigned long>(inputSize + (inputSize / 3.0) + 16);
|
||||
auto outbuf = new unsigned char[outlen]; //Reserve output memory
|
||||
if(base64_encode((unsigned char*) input, inputSize, outbuf, &outlen) != CRYPT_OK){
|
||||
std::cerr << "Invalid input '" << input << "'" << std::endl;
|
||||
//std::cerr << "Invalid input '" << input << "'" << std::endl;
|
||||
return "";
|
||||
}
|
||||
std::string ret((char*) outbuf, outlen);
|
||||
|
@ -1,4 +1,7 @@
|
||||
#ifndef NO_OPEN_SSL
|
||||
#define NO_OPEN_SSL
|
||||
#endif
|
||||
|
||||
#include "./digest.h"
|
||||
#include <tomcrypt.h>
|
||||
|
||||
|
92
src/misc/net.cpp
Normal file
92
src/misc/net.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
//
|
||||
// Created by WolverinDEV on 16/04/2020.
|
||||
//
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "./net.h"
|
||||
|
||||
namespace helpers {
|
||||
inline void strip(std::string& message) {
|
||||
while(!message.empty()) {
|
||||
if(message[0] == ' ')
|
||||
message = message.substr(1);
|
||||
else if(message[message.length() - 1] == ' ')
|
||||
message = message.substr(0, message.length() - 1);
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::deque<std::string> split(const std::string& message, char delimiter) {
|
||||
std::deque<std::string> result{};
|
||||
size_t found, index = 0;
|
||||
do {
|
||||
found = message.find(delimiter, index);
|
||||
result.push_back(message.substr(index, found - index));
|
||||
index = found + 1;
|
||||
} while(index != 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::tuple<std::string, sockaddr_storage, std::string>> net::resolve_bindings(const std::string& bindings, uint16_t port) {
|
||||
auto binding_list = helpers::split(bindings, ',');
|
||||
std::vector<std::tuple<std::string, sockaddr_storage, std::string>> result;
|
||||
result.reserve(binding_list.size());
|
||||
|
||||
for(auto& address : binding_list) {
|
||||
helpers::strip(address);
|
||||
|
||||
sockaddr_storage element{};
|
||||
memset(&element, 0, sizeof(element));
|
||||
if(!resolve_address(address, element)) {
|
||||
result.emplace_back(address, element, "address resolve failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(element.ss_family == AF_INET) {
|
||||
((sockaddr_in*) &element)->sin_port = htons(port);
|
||||
} else if(element.ss_family == AF_INET6) {
|
||||
((sockaddr_in6*) &element)->sin6_port = htons(port);
|
||||
}
|
||||
result.emplace_back(address, element, "");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
net::binding_result net::address_available(const sockaddr_storage& address, binding_type type) {
|
||||
int file_descriptor{0};
|
||||
net::binding_result result{binding_result::INTERNAL_ERROR};
|
||||
int disable{0}, enable{1};
|
||||
|
||||
file_descriptor = socket(address.ss_family, type == binding_type::TCP ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
if(file_descriptor <= 0)
|
||||
goto cleanup_exit;
|
||||
|
||||
fcntl(file_descriptor, F_SETFD, FD_CLOEXEC); /* just to ensure */
|
||||
setsockopt(file_descriptor, SOL_SOCKET, SO_REUSEADDR, &disable, sizeof(int));
|
||||
setsockopt(file_descriptor, SOL_SOCKET, SO_REUSEPORT, &disable, sizeof(int));
|
||||
if(type == binding_type::UDP && address.ss_family == AF_INET6)
|
||||
setsockopt(file_descriptor, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(int));
|
||||
|
||||
if(::bind(file_descriptor, (const sockaddr*) &address, net::address_size(address)) != 0) {
|
||||
result = binding_result::ADDRESS_USED;
|
||||
} else {
|
||||
result = binding_result::ADDRESS_FREE;
|
||||
}
|
||||
|
||||
if(type == binding_type::TCP) {
|
||||
if(::listen(file_descriptor, 1) != 0)
|
||||
result = binding_result::ADDRESS_USED;
|
||||
}
|
||||
|
||||
cleanup_exit:
|
||||
if(file_descriptor > 0)
|
||||
::close(file_descriptor);
|
||||
return result;
|
||||
}
|
||||
#endif
|
@ -4,8 +4,11 @@
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef WIN32
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS /* gethostbyname is deprecated for windows */
|
||||
#include <WS2tcpip.h>
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
@ -18,19 +21,19 @@
|
||||
#endif
|
||||
|
||||
namespace net {
|
||||
inline std::string to_string(const in6_addr& address) {
|
||||
[[nodiscard]] inline std::string to_string(const in6_addr& address) {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
if(!inet_ntop(AF_INET6, (void*) &address, buffer, INET6_ADDRSTRLEN)) return "";
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
inline std::string to_string(const in_addr& address) {
|
||||
[[nodiscard]] inline std::string to_string(const in_addr& address) {
|
||||
char buffer[INET_ADDRSTRLEN];
|
||||
if(!inet_ntop(AF_INET, (void*) &address, buffer, INET_ADDRSTRLEN)) return "";
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
inline std::string to_string(const sockaddr_storage& address, bool port = true) {
|
||||
[[nodiscard]] inline std::string to_string(const sockaddr_storage& address, bool port = true) {
|
||||
switch(address.ss_family) {
|
||||
case AF_INET:
|
||||
return to_string(((sockaddr_in*) &address)->sin_addr) + (port ? ":" + std::to_string(htons(((sockaddr_in*) &address)->sin_port)) : "");
|
||||
@ -41,7 +44,7 @@ namespace net {
|
||||
}
|
||||
}
|
||||
|
||||
inline uint16_t port(const sockaddr_storage& address) {
|
||||
[[nodiscard]] inline uint16_t port(const sockaddr_storage& address) {
|
||||
switch(address.ss_family) {
|
||||
case AF_INET:
|
||||
return htons(((sockaddr_in*) &address)->sin_port);
|
||||
@ -52,7 +55,7 @@ namespace net {
|
||||
}
|
||||
}
|
||||
|
||||
inline socklen_t address_size(const sockaddr_storage& address) {
|
||||
[[nodiscard]] inline socklen_t address_size(const sockaddr_storage& address) {
|
||||
switch (address.ss_family) {
|
||||
case AF_INET: return sizeof(sockaddr_in);
|
||||
case AF_INET6: return sizeof(sockaddr_in6);
|
||||
@ -60,7 +63,7 @@ namespace net {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool address_equal(const sockaddr_storage& a, const sockaddr_storage& b) {
|
||||
[[nodiscard]] inline bool address_equal(const sockaddr_storage& a, const sockaddr_storage& b) {
|
||||
if(a.ss_family != b.ss_family) return false;
|
||||
if(a.ss_family == AF_INET) return ((sockaddr_in*) &a)->sin_addr.s_addr == ((sockaddr_in*) &b)->sin_addr.s_addr;
|
||||
else if(a.ss_family == AF_INET6) {
|
||||
@ -73,7 +76,7 @@ namespace net {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool address_equal_ranged(const sockaddr_storage& a, const sockaddr_storage& b, uint8_t range) {
|
||||
[[nodiscard]] inline bool address_equal_ranged(const sockaddr_storage& a, const sockaddr_storage& b, uint8_t range) {
|
||||
if(a.ss_family != b.ss_family) return false;
|
||||
if(a.ss_family == AF_INET) {
|
||||
auto address_a = ((sockaddr_in*) &a)->sin_addr.s_addr;
|
||||
@ -130,17 +133,17 @@ namespace net {
|
||||
}
|
||||
|
||||
|
||||
inline bool is_ipv6(const std::string& str) {
|
||||
[[nodiscard]] inline bool is_ipv6(const std::string& str) {
|
||||
sockaddr_in6 sa{};
|
||||
return inet_pton(AF_INET6, str.c_str(), &(sa.sin6_addr)) != 0;
|
||||
}
|
||||
|
||||
inline bool is_ipv4(const std::string& str) {
|
||||
[[nodiscard]] inline bool is_ipv4(const std::string& str) {
|
||||
sockaddr_in sa{};
|
||||
return inet_pton(AF_INET, str.c_str(), &(sa.sin_addr)) != 0;
|
||||
}
|
||||
|
||||
inline bool is_anybind(sockaddr_storage& storage) {
|
||||
[[nodiscard]] inline bool is_anybind(sockaddr_storage& storage) {
|
||||
if(storage.ss_family == AF_INET) {
|
||||
auto data = (sockaddr_in*) &storage;
|
||||
return data->sin_addr.s_addr == 0;
|
||||
@ -165,7 +168,7 @@ namespace net {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool resolve_address(const std::string& address, sockaddr_storage& result) {
|
||||
[[nodiscard]] inline bool resolve_address(const std::string& address, sockaddr_storage& result) {
|
||||
if(is_ipv4(address)) {
|
||||
sockaddr_in s{};
|
||||
s.sin_port = 0;
|
||||
@ -210,51 +213,18 @@ namespace net {
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace helpers {
|
||||
inline void strip(std::string& message) {
|
||||
while(!message.empty()) {
|
||||
if(message[0] == ' ')
|
||||
message = message.substr(1);
|
||||
else if(message[message.length() - 1] == ' ')
|
||||
message = message.substr(0, message.length() - 1);
|
||||
else break;
|
||||
}
|
||||
}
|
||||
[[nodiscard]] std::vector<std::tuple<std::string, sockaddr_storage, std::string>> resolve_bindings(const std::string& bindings, uint16_t port);
|
||||
|
||||
inline std::deque<std::string> split(const std::string& message, char delimiter) {
|
||||
std::deque<std::string> result{};
|
||||
size_t found, index = 0;
|
||||
do {
|
||||
found = message.find(delimiter, index);
|
||||
result.push_back(message.substr(index, found - index));
|
||||
index = found + 1;
|
||||
} while(index != 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
enum struct binding_result {
|
||||
ADDRESS_FREE,
|
||||
ADDRESS_USED,
|
||||
INTERNAL_ERROR
|
||||
};
|
||||
|
||||
inline std::vector<std::tuple<std::string, sockaddr_storage, std::string>> resolve_bindings(const std::string& bindings, uint16_t port) {
|
||||
auto binding_list = helpers::split(bindings, ',');
|
||||
std::vector<std::tuple<std::string, sockaddr_storage, std::string>> result;
|
||||
result.reserve(binding_list.size());
|
||||
enum struct binding_type {
|
||||
TCP,
|
||||
UDP
|
||||
};
|
||||
|
||||
for(auto& address : binding_list) {
|
||||
helpers::strip(address);
|
||||
|
||||
sockaddr_storage element{};
|
||||
memset(&element, 0, sizeof(element));
|
||||
if(!resolve_address(address, element)) {
|
||||
result.emplace_back(address, element, "address resolve failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(element.ss_family == AF_INET) {
|
||||
((sockaddr_in*) &element)->sin_port = htons(port);
|
||||
} else if(element.ss_family == AF_INET6) {
|
||||
((sockaddr_in6*) &element)->sin6_port = htons(port);
|
||||
}
|
||||
result.emplace_back(address, element, "");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
[[nodiscard]] binding_result address_available(const sockaddr_storage& address, binding_type type);
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
@ -70,7 +72,7 @@ namespace str_obf {
|
||||
static_assert(sizeof(char_t) == 1, "Currently only 8 bit supported");
|
||||
if(length == 0) return;
|
||||
if(key.size() == 0) _invalid_key_size();
|
||||
if(key.size() & (key.size() - 1)) _invalid_key_size(); /* key must be an power of 2 */
|
||||
if(key.size() & (key.size() - 1UL)) _invalid_key_size(); /* key must be an power of 2 */
|
||||
|
||||
auto left = length;
|
||||
size_t key_index{0};
|
||||
@ -138,7 +140,7 @@ namespace str_obf {
|
||||
length = (std::uint64_t) ((internal::rng32_next(rng_base, (uint32_t) seed) >> 12UL) & 0xFFUL);
|
||||
} while(length == 0 || length > power2);
|
||||
|
||||
return 1U << length;
|
||||
return uint64_t{1} << length;
|
||||
}
|
||||
|
||||
template <uint64_t line_number, std::uint64_t message_size>
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "AcknowledgeManager.h"
|
||||
#include <cmath>
|
||||
#include <misc/endianness.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace ts;
|
||||
using namespace ts::connection;
|
||||
@ -41,12 +42,12 @@ void AcknowledgeManager::process_packet(ts::protocol::BasicPacket &packet) {
|
||||
entry->buffer = packet.buffer();
|
||||
|
||||
entry->resend_count = 0;
|
||||
entry->resend_period = milliseconds((int) ceil(this->average_response * 3/2));
|
||||
entry->first_send = system_clock::now();
|
||||
entry->next_resend = entry->first_send + entry->resend_period;
|
||||
entry->next_resend = entry->first_send + std::chrono::milliseconds{(int64_t) ceil(this->rto)};
|
||||
|
||||
entry->packet_type = packet.type().type();
|
||||
entry->packet_id = packet.packetId();
|
||||
entry->generation_id = packet.generationId();
|
||||
|
||||
entry->acknowledged = false;
|
||||
entry->send_count = 1;
|
||||
@ -56,11 +57,8 @@ void AcknowledgeManager::process_packet(ts::protocol::BasicPacket &packet) {
|
||||
}
|
||||
}
|
||||
|
||||
bool AcknowledgeManager::process_acknowledge(uint8_t packet_type, const pipes::buffer_view& payload, std::string& error) {
|
||||
if(payload.length() < 2) return false;
|
||||
|
||||
bool AcknowledgeManager::process_acknowledge(uint8_t packet_type, uint16_t target_id, std::string& error) {
|
||||
PacketType target_type{packet_type == protocol::ACK_LOW ? PacketType::COMMAND_LOW : PacketType::COMMAND};
|
||||
uint16_t target_id{be2le16((char*) payload.data_ptr())};
|
||||
|
||||
std::shared_ptr<Entry> entry;
|
||||
std::unique_ptr<threads::Future<bool>> ack_listener;
|
||||
@ -72,8 +70,13 @@ bool AcknowledgeManager::process_acknowledge(uint8_t packet_type, const pipes::b
|
||||
ack_listener = std::move(entry->acknowledge_listener); /* move it out so nobody else could call it as well */
|
||||
|
||||
entry->send_count--;
|
||||
if(entry->send_count == 0)
|
||||
if(entry->send_count == 0) {
|
||||
this->entries.erase(it);
|
||||
if(entry->resend_count == 0) {
|
||||
auto difference = std::chrono::system_clock::now() - entry->first_send;
|
||||
this->update_rto(std::chrono::duration_cast<std::chrono::milliseconds>(difference).count());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -83,18 +86,12 @@ bool AcknowledgeManager::process_acknowledge(uint8_t packet_type, const pipes::b
|
||||
return false;
|
||||
}
|
||||
|
||||
auto time = system_clock::now() - entry->next_resend + entry->resend_period;
|
||||
auto ms_time = duration_cast<milliseconds>(time).count();
|
||||
if(ms_time > 5) {
|
||||
this->average_response = this->average_response * .80 + ms_time * .2;
|
||||
}
|
||||
|
||||
entry->acknowledged = true;
|
||||
if(ack_listener) ack_listener->executionSucceed(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t AcknowledgeManager::execute_resend(const system_clock::time_point& now , std::chrono::system_clock::time_point &next_resend,std::deque<pipes::buffer>& buffers, string& error) {
|
||||
ssize_t AcknowledgeManager::execute_resend(const system_clock::time_point& now , std::chrono::system_clock::time_point &next_resend,std::deque<std::shared_ptr<Entry>>& buffers, string& error) {
|
||||
size_t resend_count{0};
|
||||
|
||||
vector<shared_ptr<Entry>> need_resend;
|
||||
@ -105,20 +102,16 @@ ssize_t AcknowledgeManager::execute_resend(const system_clock::time_point& now ,
|
||||
|
||||
for (auto &entry : this->entries) {
|
||||
if(entry->acknowledged) {
|
||||
if(entry->next_resend + entry->resend_period <= now) { // Some resends are lost. So we just drop it after time
|
||||
if(entry->next_resend + std::chrono::milliseconds{(int64_t) ceil(this->rto * 4)} <= now) { // Some resends are lost. So we just drop it after time
|
||||
entry.reset();
|
||||
cleanup = true;
|
||||
}
|
||||
} else {
|
||||
if(entry->next_resend <= now) {
|
||||
entry->resend_period = entry->resend_period + milliseconds{(int) ceil(this->average_response * 2)};
|
||||
if(entry->resend_period.count() > 1000)
|
||||
entry->resend_period = milliseconds(1000);
|
||||
else if(entry->resend_period.count() < 25)
|
||||
entry->resend_period = milliseconds(25);
|
||||
|
||||
entry->next_resend = now + entry->resend_period;
|
||||
entry->next_resend = now + std::chrono::milliseconds{(int64_t) std::min(ceil(this->rto), 1500.f)};
|
||||
need_resend.push_back(entry);
|
||||
entry->resend_count++;
|
||||
entry->send_count++;
|
||||
}
|
||||
if(next_resend > entry->next_resend)
|
||||
next_resend = entry->next_resend;
|
||||
@ -138,10 +131,21 @@ ssize_t AcknowledgeManager::execute_resend(const system_clock::time_point& now ,
|
||||
}
|
||||
|
||||
resend_count++;
|
||||
packet->resend_count++;
|
||||
packet->send_count++;
|
||||
buffers.push_back(packet->buffer);
|
||||
buffers.push_back(packet);
|
||||
}
|
||||
|
||||
return resend_count;
|
||||
}
|
||||
|
||||
/* we're not taking the clock granularity into account because its nearly 1ms and it would only add more branches */
|
||||
void AcknowledgeManager::update_rto(size_t r) {
|
||||
if(srtt == -1) {
|
||||
this->srtt = (float) r;
|
||||
this->rttvar = r / 2.f;
|
||||
this->rto = srtt + 4 * this->rttvar;
|
||||
} else {
|
||||
this->rttvar = (1.f - alpha) * this->rttvar + beta * abs(this->srtt - r);
|
||||
this->srtt = (1.f - alpha) * srtt + alpha * r;
|
||||
this->rto = std::max(200.f, this->srtt + 4 * this->rttvar);
|
||||
}
|
||||
}
|
@ -7,22 +7,23 @@
|
||||
namespace ts::connection {
|
||||
class VoiceClientConnection;
|
||||
class AcknowledgeManager {
|
||||
struct Entry {
|
||||
uint16_t packet_id = 0;
|
||||
uint8_t packet_type = 0xFF;
|
||||
uint8_t resend_count = 0;
|
||||
bool acknowledged : 1;
|
||||
uint8_t send_count : 7;
|
||||
|
||||
|
||||
pipes::buffer buffer;
|
||||
std::chrono::system_clock::time_point first_send;
|
||||
std::chrono::system_clock::time_point next_resend;
|
||||
std::chrono::milliseconds resend_period;
|
||||
|
||||
std::unique_ptr<threads::Future<bool>> acknowledge_listener;
|
||||
};
|
||||
public:
|
||||
struct Entry {
|
||||
uint16_t packet_id{0};
|
||||
uint16_t generation_id{0};
|
||||
|
||||
uint8_t packet_type{0xFF};
|
||||
uint8_t resend_count{0};
|
||||
bool acknowledged : 1;
|
||||
uint8_t send_count : 7;
|
||||
|
||||
|
||||
pipes::buffer buffer;
|
||||
std::chrono::system_clock::time_point first_send;
|
||||
std::chrono::system_clock::time_point next_resend;
|
||||
std::unique_ptr<threads::Future<bool>> acknowledge_listener;
|
||||
};
|
||||
|
||||
AcknowledgeManager();
|
||||
virtual ~AcknowledgeManager();
|
||||
|
||||
@ -30,20 +31,29 @@ namespace ts::connection {
|
||||
void reset();
|
||||
|
||||
void process_packet(ts::protocol::BasicPacket& /* packet */);
|
||||
bool process_acknowledge(uint8_t packet_type, const pipes::buffer_view& /* payload */, std::string& /* error */);
|
||||
bool process_acknowledge(uint8_t packet_type, uint16_t /* packet id */, std::string& /* error */);
|
||||
|
||||
ssize_t execute_resend(
|
||||
const std::chrono::system_clock::time_point& /* now */,
|
||||
std::chrono::system_clock::time_point& /* next resend */,
|
||||
std::deque<pipes::buffer>& /* buffers to resend */,
|
||||
std::deque<std::shared_ptr<Entry>>& /* buffers to resend */,
|
||||
std::string& /* error */
|
||||
);
|
||||
|
||||
[[nodiscard]] inline auto current_rto() const { return this->rto; }
|
||||
[[nodiscard]] inline auto current_srtt() const { return this->srtt; }
|
||||
[[nodiscard]] inline auto current_rttvar() const { return this->rttvar; }
|
||||
private:
|
||||
std::mutex entry_lock;
|
||||
std::deque<std::shared_ptr<Entry>> entries;
|
||||
|
||||
std::chrono::milliseconds resend_delay{500};
|
||||
float rto{1000};
|
||||
float srtt{-1};
|
||||
float rttvar{};
|
||||
|
||||
double average_response = 20;
|
||||
constexpr static auto alpha{.125f};
|
||||
constexpr static auto beta{.25f};
|
||||
|
||||
void update_rto(size_t /* response time */);
|
||||
};
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
#include <csignal>
|
||||
#include <misc/memtracker.h>
|
||||
#include "CompressionHandler.h"
|
||||
#define QLZ_COMPRESSION_LEVEL 1
|
||||
@ -39,17 +38,38 @@ namespace ts::compression {
|
||||
void* buffer_ptr{nullptr};
|
||||
size_t buffer_length{0};
|
||||
};
|
||||
|
||||
class qlz_states {
|
||||
public:
|
||||
qlz_states() noexcept {
|
||||
this->state_compress = (qlz_state_compress*) malloc(sizeof(qlz_state_compress));
|
||||
this->state_decompress = (qlz_state_decompress*) malloc(sizeof(qlz_state_decompress));
|
||||
}
|
||||
|
||||
~qlz_states() {
|
||||
::free(this->state_compress);
|
||||
::free(this->state_decompress);
|
||||
}
|
||||
|
||||
qlz_state_compress* state_compress{nullptr};
|
||||
qlz_state_decompress* state_decompress{nullptr};
|
||||
private:
|
||||
};
|
||||
|
||||
thread_local thread_buffer qlz_buffer{};
|
||||
thread_local qlz_states qlz_states{};
|
||||
|
||||
size_t qlz_decompressed_size(const void* payload, size_t payload_length) {
|
||||
if(payload_length < 9) return 0; /* payload too small */
|
||||
|
||||
return qlz_size_decompressed((char*) payload) + 400;
|
||||
}
|
||||
|
||||
bool qlz_decompress_payload(const void* payload, void* buffer, size_t* buffer_size) {
|
||||
if(!qlz_states.state_decompress) return false;
|
||||
assert(payload != buffer);
|
||||
|
||||
qlz_state_decompress state{};
|
||||
size_t data_length = qlz_decompress((char*) payload, (char*) buffer, &state);
|
||||
size_t data_length = qlz_decompress((char*) payload, (char*) buffer, qlz_states.state_decompress);
|
||||
if(data_length <= 0)
|
||||
return false;
|
||||
|
||||
@ -60,16 +80,18 @@ namespace ts::compression {
|
||||
}
|
||||
|
||||
size_t qlz_compressed_size(const void* payload, size_t payload_length) {
|
||||
assert(payload_length >= 9);
|
||||
//// "Always allocate size + 400 bytes for the destination buffer when compressing." <= http://www.quicklz.com/manual.html
|
||||
return max(min(payload_length * 2, (size_t) (payload_length + 400ULL)), (size_t) 24ULL); /* at least 12 bytes (QLZ header) */
|
||||
}
|
||||
|
||||
bool qlz_compress_payload(const void* payload, size_t payload_length, void* buffer, size_t* buffer_length) {
|
||||
if(!qlz_states.state_compress) return false;
|
||||
|
||||
assert(payload != buffer);
|
||||
assert(*buffer_length >= qlz_compressed_size(payload, payload_length));
|
||||
|
||||
qlz_state_compress state{};
|
||||
size_t compressed_length = qlz_compress(payload, (char*) buffer, payload_length, &state);
|
||||
size_t compressed_length = qlz_compress(payload, (char*) buffer, payload_length, qlz_states.state_compress);
|
||||
if(compressed_length > *buffer_length) terminate();
|
||||
|
||||
if(compressed_length <= 0)
|
||||
@ -99,6 +121,9 @@ bool CompressionHandler::decompress(protocol::BasicPacket* packet, std::string &
|
||||
if(expected_length > this->max_packet_size){ //Max 16MB. (97% Compression!)
|
||||
error = "Invalid packet size. (Calculated target length of " + to_string(expected_length) + ". Max length: " + to_string(this->max_packet_size) + ")";
|
||||
return false;
|
||||
} else if(expected_length == 0) {
|
||||
error = "Failed to calculate decompressed packet length";
|
||||
return false;
|
||||
}
|
||||
auto header_length = packet->header().length() + packet->mac().length();
|
||||
auto buffer = buffer::allocate_buffer(expected_length + header_length);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
namespace ts {
|
||||
namespace compression {
|
||||
/* Attention: These methods does not validate the data! */
|
||||
size_t qlz_decompressed_size(const void* payload, size_t payload_length);
|
||||
bool qlz_decompress_payload(const void* payload, void* buffer, size_t* buffer_size); //Attention: payload & buffer must be differen!
|
||||
|
||||
|
@ -216,27 +216,32 @@ namespace ts {
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
/* New packet parser API */
|
||||
bool PacketParser::is_encrypted() const {
|
||||
if(this->decrypted) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Unencrypted) == 0;
|
||||
}
|
||||
|
||||
bool ClientPacketParser::is_compressed() const {
|
||||
bool PacketParser::is_compressed() const {
|
||||
if(this->uncompressed) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Compressed) > 0;
|
||||
}
|
||||
|
||||
bool ClientPacketParser::is_fragmented() const {
|
||||
bool PacketParser::is_fragmented() const {
|
||||
if(this->defragmented) return false;
|
||||
|
||||
return (this->flags() & PacketFlag::Fragmented) > 0;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
uint16_t ServerPacketParser::packet_id() const { return be2le16(this->_buffer.data_ptr<uint8_t>(), ClientPacketParser::kHeaderOffset + 0); }
|
||||
uint8_t ServerPacketParser::type() const { return (uint8_t) this->_buffer[ClientPacketParser::kHeaderOffset + 2] & 0xFU; }
|
||||
uint8_t ServerPacketParser::flags() const { return (uint8_t) this->_buffer[ClientPacketParser::kHeaderOffset + 2] & 0xF0U; }
|
||||
}
|
||||
}
|
@ -286,32 +286,23 @@ namespace ts {
|
||||
void setPacketId(uint16_t, uint16_t) override;
|
||||
};
|
||||
|
||||
class ClientPacketParser {
|
||||
class PacketParser {
|
||||
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;
|
||||
}
|
||||
PacketParser(const PacketParser&) = delete;
|
||||
explicit PacketParser(pipes::buffer_view buffer) : _buffer{std::move(buffer)} {}
|
||||
|
||||
[[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]] virtual pipes::buffer_view payload() const = 0;
|
||||
[[nodiscard]] virtual size_t payload_length() const = 0;
|
||||
|
||||
[[nodiscard]] uint16_t client_id() const;
|
||||
[[nodiscard]] uint16_t packet_id() const;
|
||||
[[nodiscard]] uint8_t type() const;
|
||||
[[nodiscard]] uint8_t flags() const;
|
||||
[[nodiscard]] inline uint32_t full_packet_id() const { return this->packet_id() | (this->estimated_generation() << 16U); }
|
||||
[[nodiscard]] virtual uint16_t packet_id() const = 0;
|
||||
[[nodiscard]] virtual uint8_t type() const = 0;
|
||||
[[nodiscard]] virtual uint8_t flags() const = 0;
|
||||
|
||||
[[nodiscard]] bool is_encrypted() const;
|
||||
[[nodiscard]] bool is_compressed() const;
|
||||
@ -323,12 +314,36 @@ namespace ts {
|
||||
inline void set_decrypted() { this->decrypted = true; }
|
||||
inline void set_uncompressed() { this->uncompressed = true; }
|
||||
inline void set_defragmented() { this->defragmented = true; }
|
||||
private:
|
||||
|
||||
protected:
|
||||
uint16_t generation{};
|
||||
bool decrypted{false}, uncompressed{false}, defragmented{false};
|
||||
pipes::buffer_view _buffer{};
|
||||
};
|
||||
|
||||
class ClientPacketParser : public PacketParser {
|
||||
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) : PacketParser{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 pipes::buffer_view payload() const override { return this->_buffer.view(kPayloadOffset); }
|
||||
[[nodiscard]] inline size_t payload_length() const override { return this->_buffer.length() - kPayloadOffset; }
|
||||
|
||||
[[nodiscard]] uint16_t client_id() const;
|
||||
[[nodiscard]] uint16_t packet_id() const override;
|
||||
[[nodiscard]] uint8_t type() const override;
|
||||
[[nodiscard]] uint8_t flags() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Packet from the server
|
||||
*/
|
||||
@ -367,5 +382,27 @@ namespace ts {
|
||||
|
||||
void setPacketId(uint16_t, uint16_t) override;
|
||||
};
|
||||
|
||||
class ServerPacketParser : public PacketParser {
|
||||
public:
|
||||
constexpr static auto kHeaderOffset = 8;
|
||||
constexpr static auto kHeaderLength = SERVER_HEADER_SIZE;
|
||||
|
||||
constexpr static auto kPayloadOffset = kHeaderOffset + SERVER_HEADER_SIZE;
|
||||
explicit ServerPacketParser(pipes::buffer_view buffer) : PacketParser{std::move(buffer)} {}
|
||||
ServerPacketParser(const ServerPacketParser&) = delete;
|
||||
|
||||
[[nodiscard]] inline bool valid() const {
|
||||
if(this->_buffer.length() < kPayloadOffset) return false;
|
||||
return this->type() <= 8;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pipes::buffer_view payload() const override { return this->_buffer.view(kPayloadOffset); }
|
||||
[[nodiscard]] inline size_t payload_length() const override { return this->_buffer.length() - kPayloadOffset; }
|
||||
|
||||
[[nodiscard]] uint16_t packet_id() const override;
|
||||
[[nodiscard]] uint8_t type() const override;
|
||||
[[nodiscard]] uint8_t flags() const override;
|
||||
};
|
||||
}
|
||||
}
|
129
src/protocol/PacketLossCalculator.cpp
Normal file
129
src/protocol/PacketLossCalculator.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
//
|
||||
// Created by WolverinDEV on 06/04/2020.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
#include "PacketLossCalculator.h"
|
||||
|
||||
using namespace ts::protocol;
|
||||
|
||||
void UnorderedPacketLossCalculator::packet_received(uint32_t packet_id) {
|
||||
if(packet_id > this->packet_history_offset) {
|
||||
const auto age = packet_id - this->packet_history_offset; /* best case should be 1 */
|
||||
|
||||
if(age < this->packet_history.max_bits()) {
|
||||
const auto received = this->packet_history.shift_in_bounds(age).count();
|
||||
this->received_packets_ += (uint32_t) received;
|
||||
this->received_packets_total_ += (uint32_t) received;
|
||||
|
||||
this->lost_packets_ += (uint32_t) (age - received);
|
||||
this->lost_packets_total_ += (uint32_t) (age - received);
|
||||
} else {
|
||||
const auto received = this->packet_history.clear().count();
|
||||
this->received_packets_ += (uint32_t) received;
|
||||
this->received_packets_total_ += (uint32_t) received;
|
||||
this->lost_packets_ += (uint32_t) (this->packet_history.max_bits() - received);
|
||||
this->lost_packets_total_ += (uint32_t) (this->packet_history.max_bits() - received);
|
||||
|
||||
if(age >= this->packet_history.max_bits() * 2) {
|
||||
this->packet_history.set_unchecked(0);
|
||||
this->lost_packets_ += (uint32_t) (age - this->packet_history.max_bits() * 2);
|
||||
this->lost_packets_total_ += (uint32_t) (age - this->packet_history.max_bits() * 2);
|
||||
} else {
|
||||
this->packet_history.set_unchecked(age - this->packet_history.max_bits());
|
||||
}
|
||||
}
|
||||
this->packet_history.set_unchecked(0);
|
||||
this->packet_history_offset = packet_id;
|
||||
if(packet_id < this->packet_history.max_bits()) {
|
||||
this->received_packets_ = 0;
|
||||
this->received_packets_total_ = 0;
|
||||
this->lost_packets_ = 0;
|
||||
this->lost_packets_total_ = 0;
|
||||
}
|
||||
} else {
|
||||
/* unordered packet */
|
||||
const auto age = this->packet_history_offset - packet_id;
|
||||
if(age >= this->packet_history.max_bits())
|
||||
return; /* well that packet is way too old */
|
||||
|
||||
this->packet_history.set_unchecked(age);
|
||||
}
|
||||
}
|
||||
|
||||
void UnorderedPacketLossCalculator::short_stats() {
|
||||
constexpr auto target_interval = 32;
|
||||
|
||||
const auto packets_passed = this->packet_history_offset - this->last_history_offset;
|
||||
if(packets_passed < target_interval) return;
|
||||
|
||||
const auto factor = .5;
|
||||
this->received_packets_ = (uint32_t) (this->received_packets_ * factor);
|
||||
this->lost_packets_ = (uint32_t) (this->lost_packets_ * factor);
|
||||
this->last_history_offset = this->packet_history_offset;
|
||||
}
|
||||
|
||||
void UnorderedPacketLossCalculator::reset() {
|
||||
this->received_packets_ = 0;
|
||||
this->received_packets_total_ = 0;
|
||||
this->lost_packets_ = 0;
|
||||
this->lost_packets_total_ = 0;
|
||||
this->reset_offsets();
|
||||
}
|
||||
void UnorderedPacketLossCalculator::reset_offsets() {
|
||||
this->packet_history_offset = 0;
|
||||
this->last_history_offset = 0;
|
||||
this->packet_history.clear();
|
||||
}
|
||||
|
||||
void CommandPacketLossCalculator::packet_send(uint32_t packet_id) {
|
||||
if(packet_id > this->packet_history_offset) {
|
||||
assert(packet_id - 1 == this->packet_history_offset); /* the method will only be called with an incrementing packet id */
|
||||
/* newly send packet */
|
||||
auto lost = std::exchange(this->packet_ack_counts[packet_id % CommandPacketLossCalculator::packet_ack_counts_length], 1);
|
||||
this->lost_packets_ += lost;
|
||||
this->lost_packets_total_ += lost;
|
||||
this->packet_history_offset = packet_id;
|
||||
} else {
|
||||
/* We're not really interested if the packet id matches the resend packet. If not we may accidentally increase the loss count. */
|
||||
this->packet_ack_counts[packet_id % CommandPacketLossCalculator::packet_ack_counts_length]++;
|
||||
}
|
||||
this->packets_send_unshorten++;
|
||||
}
|
||||
|
||||
void CommandPacketLossCalculator::ack_received(uint32_t packet_id) {
|
||||
auto& count = this->packet_ack_counts[packet_id % CommandPacketLossCalculator::packet_ack_counts_length];
|
||||
if(count > 0) /* could happen if receive an acknowledge for an packet which is older than out buffer size or the client send the ack twice... */
|
||||
count--;
|
||||
|
||||
this->received_packets_++;
|
||||
this->received_packets_total_++;
|
||||
}
|
||||
|
||||
void CommandPacketLossCalculator::short_stats() {
|
||||
constexpr auto target_interval = 64;
|
||||
|
||||
const auto packets_passed = this->packets_send_unshorten;
|
||||
if(packets_passed < target_interval) return;
|
||||
this->packets_send_unshorten = 0;
|
||||
|
||||
const auto factor = target_interval / packets_passed;
|
||||
this->received_packets_ *= factor;
|
||||
this->lost_packets_ *= factor;
|
||||
}
|
||||
|
||||
void CommandPacketLossCalculator::reset() {
|
||||
this->received_packets_ = 0;
|
||||
this->received_packets_total_ = 0;
|
||||
this->lost_packets_ = 0;
|
||||
this->lost_packets_total_ = 0;
|
||||
this->reset_offsets();
|
||||
}
|
||||
|
||||
void CommandPacketLossCalculator::reset_offsets() {
|
||||
this->packet_history_offset = 0;
|
||||
this->packets_send_unshorten = 0;
|
||||
memset(packet_ack_counts, 0, packet_ack_counts_length);
|
||||
}
|
106
src/protocol/PacketLossCalculator.h
Normal file
106
src/protocol/PacketLossCalculator.h
Normal file
@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <bitset>
|
||||
|
||||
namespace ts::protocol {
|
||||
template <size_t N>
|
||||
struct bit_set;
|
||||
|
||||
template <>
|
||||
struct bit_set<32> {
|
||||
constexpr static auto native_memory_bytes = sizeof(uint32_t);
|
||||
constexpr static auto native_memory_bits = native_memory_bytes * 8;
|
||||
public:
|
||||
bit_set() : memory{0} {}
|
||||
explicit bit_set(uint32_t mem) : memory{mem} {}
|
||||
|
||||
[[nodiscard]] inline auto max_bits() const { return native_memory_bits; }
|
||||
|
||||
inline auto shift_in_bounds(size_t offset) {
|
||||
assert(offset <= this->native_memory_bits);
|
||||
|
||||
auto result = bit_set<native_memory_bits>{this->memory >> (native_memory_bits - offset)};
|
||||
this->memory <<= offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void set_unchecked(size_t offset) {
|
||||
this->memory |= 1U << offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto count() const {
|
||||
/* std::bitset will get optimized away */
|
||||
return std::bitset<32>(this->memory).count();
|
||||
}
|
||||
|
||||
inline auto clear() { return bit_set<native_memory_bits>{std::exchange(this->memory, 0)}; }
|
||||
private:
|
||||
uint32_t memory;
|
||||
};
|
||||
|
||||
/* will we ever have more than 2^32 packets? Hell no. That would be over (2^32 / (50 * 60 * 60 * 24) := 994.2 days continuous speaking */
|
||||
class UnorderedPacketLossCalculator {
|
||||
public:
|
||||
UnorderedPacketLossCalculator() = default;
|
||||
|
||||
void packet_received(uint32_t /* packet id */);
|
||||
void short_stats();
|
||||
void reset();
|
||||
void reset_offsets();
|
||||
|
||||
[[nodiscard]] inline auto last_packet_id() const { return this->packet_history_offset; }
|
||||
[[nodiscard]] inline bool valid_data() const { return this->packet_history_offset >= 32; }
|
||||
|
||||
[[nodiscard]] inline uint32_t received_packets() const { return this->received_packets_; }
|
||||
[[nodiscard]] inline uint32_t lost_packets() const { return this->lost_packets_; }
|
||||
|
||||
[[nodiscard]] inline uint32_t received_packets_total() const { return this->received_packets_total_; }
|
||||
[[nodiscard]] inline uint32_t lost_packets_total() const { return this->lost_packets_total_; }
|
||||
|
||||
[[nodiscard]] inline uint32_t unconfirmed_received_packets() const { return (uint32_t) this->packet_history.count(); };
|
||||
[[nodiscard]] inline uint32_t unconfirmed_lost_packets() const { return (uint32_t) (this->packet_history.max_bits() - this->packet_history.count()); };
|
||||
|
||||
private:
|
||||
uint32_t received_packets_{0}, received_packets_total_{0}, lost_packets_{0}, lost_packets_total_{0};
|
||||
|
||||
uint32_t packet_history_offset{0}, last_history_offset{0};
|
||||
bit_set<32> packet_history{};
|
||||
};
|
||||
|
||||
class CommandPacketLossCalculator {
|
||||
constexpr static auto packet_ack_counts_length{32};
|
||||
public:
|
||||
CommandPacketLossCalculator() = default;
|
||||
|
||||
void packet_send(uint32_t /* packet id */);
|
||||
void ack_received(uint32_t /* packet id */); //Attention: This is a full ID!
|
||||
|
||||
void short_stats();
|
||||
void reset();
|
||||
void reset_offsets();
|
||||
|
||||
[[nodiscard]] inline bool valid_data() const { return true; }
|
||||
|
||||
[[nodiscard]] inline uint32_t received_packets() const { return this->received_packets_; }
|
||||
[[nodiscard]] inline uint32_t lost_packets() const { return this->lost_packets_; }
|
||||
|
||||
[[nodiscard]] inline uint32_t received_packets_total() const { return this->received_packets_total_; }
|
||||
[[nodiscard]] inline uint32_t lost_packets_total() const { return this->lost_packets_total_; }
|
||||
|
||||
[[nodiscard]] inline uint32_t unconfirmed_received_packets() const { return 0; };
|
||||
[[nodiscard]] inline uint32_t unconfirmed_lost_packets() const {
|
||||
uint32_t result{0};
|
||||
for(auto& e : this->packet_ack_counts)
|
||||
result += e;
|
||||
return result;
|
||||
};
|
||||
private:
|
||||
uint32_t received_packets_{0}, received_packets_total_{0}, lost_packets_{0}, lost_packets_total_{0};
|
||||
|
||||
uint32_t packet_history_offset{0}, packets_send_unshorten{0};
|
||||
uint8_t packet_ack_counts[packet_ack_counts_length]{0};
|
||||
};
|
||||
}
|
@ -14,23 +14,27 @@ void generation_estimator::reset() {
|
||||
uint16_t generation_estimator::visit_packet(uint16_t packet_id) {
|
||||
if(this->last_packet_id >= generation_estimator::overflow_area_begin) {
|
||||
if(packet_id > this->last_packet_id) {
|
||||
/* normal behaviour */
|
||||
this->last_packet_id = packet_id;
|
||||
return this->last_generation;
|
||||
} else {
|
||||
} else if(packet_id < generation_estimator::overflow_area_end) {
|
||||
/* we're within a new generation */
|
||||
this->last_packet_id = packet_id;
|
||||
return ++this->last_generation;
|
||||
} else {
|
||||
/* old packet */
|
||||
return this->last_generation;
|
||||
}
|
||||
} else if(this->last_packet_id <= generation_estimator::overflow_area_end) {
|
||||
if(packet_id >= generation_estimator::overflow_area_begin) /* old packet */
|
||||
return this->last_generation - 1;
|
||||
this->last_packet_id = packet_id;
|
||||
if(packet_id > this->last_packet_id)
|
||||
this->last_packet_id = packet_id;
|
||||
return this->last_generation;
|
||||
} else {
|
||||
this->last_packet_id = packet_id;
|
||||
/* only update on newer packet id */
|
||||
if(packet_id > this->last_packet_id)
|
||||
this->last_packet_id = packet_id;
|
||||
return this->last_generation;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t generation_estimator::generation() const {
|
||||
return this->last_generation;
|
||||
}
|
@ -8,15 +8,16 @@ namespace ts::protocol {
|
||||
generation_estimator();
|
||||
|
||||
void reset();
|
||||
uint16_t visit_packet(uint16_t /* packet id */);
|
||||
uint16_t generation() const;
|
||||
[[nodiscard]] uint16_t visit_packet(uint16_t /* packet id */);
|
||||
[[nodiscard]] inline uint16_t generation() const { return this->last_generation; }
|
||||
[[nodiscard]] inline uint16_t current_packet_id() const { return this->last_packet_id; }
|
||||
|
||||
void set_last_state(uint16_t last_packet, uint16_t generation) {
|
||||
this->last_packet_id = last_packet;
|
||||
this->last_generation = generation;
|
||||
}
|
||||
private:
|
||||
constexpr static uint16_t overflow_window{1024};
|
||||
constexpr static uint16_t overflow_window{1024 * 8};
|
||||
constexpr static uint16_t overflow_area_begin{0xFFFF - overflow_window};
|
||||
constexpr static uint16_t overflow_area_end{overflow_window};
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <pipes/buffer.h>
|
||||
#include "log/LogUtils.h"
|
||||
#include "escape.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -141,7 +141,7 @@ operator type(){ \
|
||||
|
||||
friend std::ostream& operator<<(std::ostream&, const ValueList&);
|
||||
private:
|
||||
ValueList(std::string& key, std::deque<ParameterBulk>& bulkList) : key(key), bulkList(bulkList) {}
|
||||
ValueList(std::string key, std::deque<ParameterBulk>& bulkList) : key{std::move(key)}, bulkList(bulkList) {}
|
||||
std::string key;
|
||||
public:
|
||||
std::deque<ParameterBulk>& bulkList;
|
||||
@ -171,9 +171,9 @@ operator type(){ \
|
||||
~Command();
|
||||
|
||||
inline std::string command() const { return getCommand(); }
|
||||
std::string getCommand() const { return _command; }
|
||||
[[nodiscard]] std::string getCommand() const { return _command; }
|
||||
|
||||
std::string build(bool escaped = true) const;
|
||||
[[nodiscard]] std::string build(bool escaped = true) const;
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
Json::Value buildJson() const;
|
||||
@ -184,15 +184,24 @@ operator type(){ \
|
||||
return bulks[index];
|
||||
}
|
||||
|
||||
ParameterBulk& operator[](size_t index){
|
||||
template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||
ParameterBulk& operator[](T index){
|
||||
while(bulks.size() <= index) bulks.push_back(ParameterBulk{});
|
||||
return bulks[index];
|
||||
}
|
||||
|
||||
ValueList operator[](std::string key){
|
||||
ValueList operator[](const std::string& key){
|
||||
return ValueList(key, bulks);
|
||||
}
|
||||
|
||||
ValueList operator[](const std::string_view& key){
|
||||
return ValueList(std::string{key}, bulks); //FIXME This should not be the normal case!
|
||||
}
|
||||
|
||||
ValueList operator[](const char* key){
|
||||
return ValueList(std::string{key}, bulks); //FIXME This should not be the normal case!
|
||||
}
|
||||
|
||||
size_t bulkCount() const { return bulks.size(); }
|
||||
void pop_bulk();
|
||||
void push_bulk_front();
|
||||
|
@ -2,11 +2,12 @@
|
||||
// Created by wolverindev on 25.01.20.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include "command3.h"
|
||||
|
||||
using namespace ts;
|
||||
|
||||
command_bulk command_parser::empty_bulk{std::string::npos, ""};
|
||||
command_bulk command_parser::empty_bulk{std::string::npos, 0, ""};
|
||||
|
||||
bool command_parser::parse(bool command) {
|
||||
this->data = this->_command;
|
||||
@ -31,8 +32,22 @@ bool command_parser::parse(bool command) {
|
||||
if(findex == std::string::npos)
|
||||
findex = this->_command.size();
|
||||
|
||||
this->_bulks.emplace_back(this->_bulks.size() - 1, this->data.substr(index, findex - index));
|
||||
this->_bulks.emplace_back(this->_bulks.size() - 1, index, this->data.substr(index, findex - index));
|
||||
index = findex + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<size_t> command_parser::next_bulk_containing(const std::string_view &key, size_t start) const {
|
||||
if(start >= this->bulk_count()) return std::nullopt;
|
||||
|
||||
auto index = this->bulk(start).command_character_index();
|
||||
auto next = this->data.find(key, index);
|
||||
if(next == std::string::npos) return std::nullopt;
|
||||
|
||||
size_t upper_bulk{start + 1};
|
||||
for(; upper_bulk < this->bulk_count(); upper_bulk++)
|
||||
if(this->bulk(upper_bulk).command_character_index() > next)
|
||||
break;
|
||||
return upper_bulk - 1;
|
||||
}
|
@ -26,13 +26,16 @@ namespace ts {
|
||||
|
||||
findex += key_size;
|
||||
if(findex < max) {
|
||||
if(findex < max && data[findex] != '=') {
|
||||
if(data[findex] == '=')
|
||||
begin = findex + 1;
|
||||
else if(data[findex] == ' ')
|
||||
begin = findex; /* empty value */
|
||||
else {
|
||||
index = findex + key_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
begin = findex + 1;
|
||||
if(end) *end = data.find(' ', findex + 1);
|
||||
if(end) *end = data.find(' ', findex);
|
||||
return true;
|
||||
} else {
|
||||
begin = max;
|
||||
@ -46,6 +49,11 @@ namespace ts {
|
||||
public:
|
||||
[[nodiscard]] inline bool is_empty() const noexcept { return this->data.empty(); }
|
||||
|
||||
[[nodiscard]] inline bool has_key(const std::string_view& key) const {
|
||||
size_t begin{0};
|
||||
return value_raw_impl(this->data, key, begin, nullptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string_view value_raw(const std::string_view& key) const {
|
||||
bool tmp;
|
||||
auto result = this->value_raw(key, tmp);
|
||||
@ -54,7 +62,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string_view value_raw(const std::string_view& key, bool& has_been_found) const noexcept {
|
||||
size_t begin, end;
|
||||
size_t begin{0}, end;
|
||||
has_been_found = value_raw_impl(this->data, key, begin, &end);
|
||||
if(!has_been_found) return {};
|
||||
|
||||
@ -68,6 +76,13 @@ namespace ts {
|
||||
return query::unescape(std::string{value}, false);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string value(const std::string_view& key, bool& has_been_found) const noexcept {
|
||||
const auto value = this->value_raw(key, has_been_found);
|
||||
if(value.empty()) return std::string{};
|
||||
|
||||
return query::unescape(std::string{value}, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] inline T value_as(const std::string_view& key) const {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
@ -76,16 +91,23 @@ namespace ts {
|
||||
return converter<T>::from_string_view(this->value(key));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline size_t command_character_index() const { return this->abs_index; }
|
||||
[[nodiscard]] inline size_t key_command_character_index(const std::string_view& key) const {
|
||||
size_t begin{0};
|
||||
if(!value_raw_impl(this->data, key, begin, nullptr)) return this->abs_index;
|
||||
return this->abs_index + begin;
|
||||
}
|
||||
protected:
|
||||
command_string_parser(size_t index, std::string_view data) : index{index}, data{std::move(data)} {}
|
||||
command_string_parser(size_t index, size_t abs_index, std::string_view data) : index{index}, abs_index{abs_index}, data{data} {}
|
||||
|
||||
size_t abs_index{};
|
||||
size_t index{};
|
||||
std::string_view data{};
|
||||
};
|
||||
}
|
||||
|
||||
struct command_bulk : public impl::command_string_parser {
|
||||
command_bulk(size_t index, std::string_view data) : command_string_parser{index, std::move(data)} {}
|
||||
command_bulk(size_t index, size_t abs_index, std::string_view data) : command_string_parser{index, abs_index, data} {}
|
||||
|
||||
inline bool next_entry(size_t& index, std::string_view& key, std::string& value) const {
|
||||
auto next_key = this->data.find_first_not_of(' ', index);
|
||||
@ -119,7 +141,7 @@ namespace ts {
|
||||
failed
|
||||
};
|
||||
|
||||
explicit command_parser(std::string command) : _command{std::move(command)}, impl::command_string_parser{std::string::npos, this->_command} { }
|
||||
explicit command_parser(std::string command) : impl::command_string_parser{std::string::npos, 0, command}, _command{std::move(command)} { }
|
||||
|
||||
bool parse(bool /* contains identifier */);
|
||||
|
||||
@ -135,25 +157,101 @@ namespace ts {
|
||||
[[nodiscard]] inline bool has_switch(const std::string_view& key) const noexcept {
|
||||
size_t index{0};
|
||||
do {
|
||||
index = this->_command_view.find(key, index);
|
||||
index = this->data.find(key, index);
|
||||
index -= 1;
|
||||
if(index > key.size()) return false;
|
||||
if(this->_command_view[index] == '-') return index == 0 || this->_command_view[index - 1] == ' ';
|
||||
if(this->data[index] == '-') return index == 0 || this->data[index - 1] == ' ';
|
||||
index += 2;
|
||||
} while(true);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<command_bulk>& bulks() const { return this->_bulks; }
|
||||
|
||||
[[nodiscard]] std::optional<size_t> next_bulk_containing(const std::string_view& /* key */, size_t /* bulk offset */) const;
|
||||
private:
|
||||
static command_bulk empty_bulk;
|
||||
|
||||
const std::string _command{};
|
||||
const std::string_view _command_view{};
|
||||
|
||||
std::string_view command_type{};
|
||||
|
||||
std::vector<command_bulk> _bulks{};
|
||||
std::vector<std::string_view> flags{};
|
||||
};
|
||||
|
||||
class command_builder_bulk {
|
||||
template <typename vector_t>
|
||||
friend class command_builder_impl;
|
||||
public:
|
||||
inline void reserve(size_t length, bool accumulative = true) {
|
||||
this->bulk.reserve(length + (accumulative ? this->bulk.size() : 0));
|
||||
}
|
||||
|
||||
inline void put(const std::string_view& key, const std::string_view& value) {
|
||||
size_t begin, end;
|
||||
if(impl::value_raw_impl(this->bulk, key, begin, &end)) {
|
||||
std::string result{};
|
||||
result.reserve(this->bulk.size());
|
||||
|
||||
result.append(this->bulk, 0, begin - key.size() - 1); /* key incl = */
|
||||
result.append(this->bulk, end + 1); /* get rid of the space */
|
||||
this->bulk = result;
|
||||
}
|
||||
this->impl_put_unchecked(key, value);
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<!(std::is_same<T, std::string_view>::value || std::is_same<T, std::string>::value), int> = 1>
|
||||
inline void put(const std::string_view& key, const T& value) {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::to_string, "Target type dosn't support building");
|
||||
auto data = converter<T>::to_string(value);
|
||||
this->put(key, std::string_view{data});
|
||||
}
|
||||
|
||||
#ifdef PROPERTIES_DEFINED
|
||||
template <typename PropertyType, typename T, std::enable_if_t<std::is_enum<PropertyType>::value, int> = 0>
|
||||
inline void put(PropertyType key, const T& value) {
|
||||
this->put(property::name(key), value);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* directly puts data without checking for duplicates */
|
||||
inline void put_unchecked(const std::string_view& key, const std::string_view& value) {
|
||||
this->impl_put_unchecked(key, value);
|
||||
}
|
||||
|
||||
inline void put_unchecked(const std::string_view& key, const std::string& value) {
|
||||
this->put_unchecked(key, std::string_view{value});
|
||||
}
|
||||
|
||||
#ifdef PROPERTIES_DEFINED
|
||||
template <typename PropertyType, typename T, std::enable_if_t<std::is_enum<PropertyType>::value, int> = 0>
|
||||
inline void put_unchecked(PropertyType key, const T& value) {
|
||||
this->put_unchecked(property::name(key), value);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, std::enable_if_t<!(std::is_same<T, std::string_view>::value || std::is_same<T, std::string>::value), int> = 1>
|
||||
inline void put_unchecked(const std::string_view& key, const T& value) {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::to_string, "Target type dosn't support building");
|
||||
auto data = converter<T>::to_string(value);
|
||||
this->put_unchecked(key, std::string_view{data});
|
||||
}
|
||||
private:
|
||||
bool& flag_changed;
|
||||
std::string& bulk;
|
||||
explicit command_builder_bulk(bool& change_flag, std::string& bulk) : flag_changed{change_flag}, bulk{bulk} {}
|
||||
|
||||
void impl_put_unchecked(const std::string_view& key, const std::string_view& value) {
|
||||
auto escaped_value = ts::query::escape(std::string{value});
|
||||
|
||||
this->bulk.reserve(this->bulk.length() + key.size() + escaped_value.size() + 2);
|
||||
this->bulk.append(key);
|
||||
if(!escaped_value.empty()) {
|
||||
this->bulk.append("=");
|
||||
this->bulk.append(escaped_value);
|
||||
}
|
||||
this->bulk.append(" ");
|
||||
this->flag_changed = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename vector_t = std::vector<std::string>>
|
||||
@ -169,7 +267,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
inline std::string build(bool with_empty = false) const {
|
||||
if(this->builded.has_value())
|
||||
if(this->builded.has_value() && !this->flag_changed)
|
||||
return this->builded.value();
|
||||
|
||||
std::string result{};
|
||||
@ -189,74 +287,49 @@ namespace ts {
|
||||
this->builded = result.substr(0, result.length() - 1);
|
||||
else
|
||||
this->builded = result;
|
||||
this->flag_changed = false;
|
||||
return this->builded.value();
|
||||
}
|
||||
|
||||
inline void reserve_bulks(size_t count) { this->bulks.reserve(count); }
|
||||
|
||||
inline void put(size_t index, const std::string_view& key, const std::string_view& value) {
|
||||
[[nodiscard]] inline command_builder_bulk bulk(size_t index) {
|
||||
while(this->bulks.size() <= index)
|
||||
this->bulks.emplace_back("").reserve(expected_bulk_size);
|
||||
|
||||
auto& data = this->bulks[index];
|
||||
size_t begin, end;
|
||||
if(impl::value_raw_impl(data, key, begin, &end)) {
|
||||
std::string result{};
|
||||
result.reserve(data.size());
|
||||
|
||||
result.append(data, 0, begin - key.size() - 1); /* key incl = */
|
||||
result.append(data, end + 1); /* get rid of the space */
|
||||
data = result;
|
||||
}
|
||||
this->impl_put_unchecked(data, index, key, value);
|
||||
return command_builder_bulk{this->flag_changed, this->bulks[index]};
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<!(std::is_same<T, std::string_view>::value || std::is_same<T, std::string>::value), int> = 1>
|
||||
inline void put(size_t index, const std::string_view& key, const T& value) {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::to_string, "Target type dosn't support building");
|
||||
auto data = converter<T>::to_string(value);
|
||||
this->put(index, key, std::string_view{data});
|
||||
template <typename KeyT, typename ValueT>
|
||||
inline void put(size_t index, const KeyT& key, const ValueT& value) {
|
||||
this->bulk(index).put(key, value);
|
||||
}
|
||||
|
||||
/* directly puts data without checking for duplicates */
|
||||
inline void put_unchecked(size_t index, const std::string_view& key, const std::string_view& value) {
|
||||
while(this->bulks.size() <= index)
|
||||
this->bulks.emplace_back("").reserve(expected_bulk_size);
|
||||
|
||||
this->impl_put_unchecked(this->bulks[index], index, key, value);
|
||||
template <typename KeyT, typename ValueT>
|
||||
inline void put_unchecked(size_t index, const KeyT& key, const ValueT& value) {
|
||||
this->bulk(index).put_unchecked(key, value);
|
||||
}
|
||||
|
||||
inline void put_unchecked(size_t index, const std::string_view& key, const std::string& value) {
|
||||
this->put_unchecked(index, key, std::string_view{value});
|
||||
[[nodiscard]] inline size_t current_size() const {
|
||||
if(this->bulks.empty()) return 0;
|
||||
|
||||
size_t result{0};
|
||||
for(const auto& entry : this->bulks)
|
||||
result += entry.length() + 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<!(std::is_same<T, std::string_view>::value || std::is_same<T, std::string>::value), int> = 1>
|
||||
inline void put_unchecked(size_t index, const std::string_view& key, const T& value) {
|
||||
static_assert(converter<T>::supported, "Target type isn't supported!");
|
||||
static_assert(!converter<T>::supported || converter<T>::to_string, "Target type dosn't support building");
|
||||
auto data = converter<T>::to_string(value);
|
||||
this->put_unchecked(index, key, std::string_view{data});
|
||||
inline void reset() {
|
||||
for(auto& bulk : this->bulks)
|
||||
bulk = " ";
|
||||
}
|
||||
private:
|
||||
command_builder_impl(size_t expected, size_t identifier, typename vector_t::iterator begin, typename vector_t::iterator end) : expected_bulk_size{expected}, _identifier{identifier}, bulks{begin, end} {}
|
||||
|
||||
void impl_put_unchecked(std::string& data, size_t index, const std::string_view& key, const std::string_view& value) {
|
||||
auto escaped_value = ts::query::escape(std::string{value});
|
||||
|
||||
data.reserve(data.length() + key.size() + escaped_value.size() + 2);
|
||||
data.append(key);
|
||||
if(!escaped_value.empty()) {
|
||||
data.append("=");
|
||||
data.append(escaped_value);
|
||||
}
|
||||
data.append(" ");
|
||||
|
||||
this->builded.reset();
|
||||
}
|
||||
command_builder_impl(size_t expected, std::string identifier, typename vector_t::iterator begin, typename vector_t::iterator end) : expected_bulk_size{expected}, _identifier{std::move(identifier)}, bulks{begin, end} {}
|
||||
|
||||
const size_t expected_bulk_size;
|
||||
const std::string _identifier;
|
||||
mutable bool flag_changed{false};
|
||||
mutable std::optional<std::string> builded{};
|
||||
vector_t bulks{};
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ namespace sql {
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string fmtStr(){
|
||||
std::string fmtStr() const {
|
||||
std::stringstream s;
|
||||
operator<<(s, *this);
|
||||
return s.str();
|
||||
@ -285,12 +285,6 @@ namespace sql {
|
||||
return *(SelfType*) this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SelfType& value(const std::initializer_list<T>& val) {
|
||||
//this->_data->variables.push_back(val.begin());
|
||||
return *(SelfType*) this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SelfType& value(const std::string& key, T&& value) {
|
||||
this->_data->variables.push_back(variable{key, value});
|
||||
|
153
src/sql/insert.h
Normal file
153
src/sql/insert.h
Normal file
@ -0,0 +1,153 @@
|
||||
#pragma once
|
||||
|
||||
namespace sql {
|
||||
|
||||
template <typename T>
|
||||
struct Column {
|
||||
constexpr explicit Column(const std::string_view& name) : name{name} { }
|
||||
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
struct BindingNameGenerator {
|
||||
public:
|
||||
[[nodiscard]] static std::string generate(size_t index) {
|
||||
assert(index > 0);
|
||||
std::string result{};
|
||||
result.resize(std::max(index >> 4U, 1UL));
|
||||
for(auto it = result.begin(); index > 0; index >>= 4U)
|
||||
*(it++) = number_map[index & 0xFU];
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static std::array<char, 16> number_map{
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p'
|
||||
};
|
||||
};
|
||||
|
||||
template <typename... ColTypes>
|
||||
struct InsertQueryGenerator {
|
||||
struct GenerateOptions {
|
||||
bool enable_ignore{false};
|
||||
sql::SqlType target{sql::SqlType::TYPE_SQLITE};
|
||||
};
|
||||
|
||||
explicit InsertQueryGenerator(std::string target_table, Column<ColTypes>... columns) : table_name{std::move(target_table)}, columns{std::move(columns.name)...} { }
|
||||
|
||||
[[nodiscard]] constexpr inline auto column_count() const { return sizeof...(ColTypes); };
|
||||
|
||||
[[nodiscard]] inline std::string generate_query(size_t entry_count, sql::SqlType target = sql::SqlType::TYPE_SQLITE, bool enable_ignore = false) const {
|
||||
if(entry_count == 0) return "-- No entries given";
|
||||
|
||||
std::string result{"INSERT "};
|
||||
if(enable_ignore) {
|
||||
if(target == sql::TYPE_MYSQL)
|
||||
result += "IGNORE ";
|
||||
else
|
||||
result += "OR IGNORE ";
|
||||
}
|
||||
|
||||
result += this->table_name + " (";
|
||||
//"INSERT INTO " + this->table_name + " ("
|
||||
for(auto it = this->columns.begin();;) {
|
||||
result += "`" + *it + "`";
|
||||
if(++it != this->columns.end()) {
|
||||
result += ", ";
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result += ") VALUES (";
|
||||
for(size_t index{1}; index <= this->column_count() * entry_count; index++)
|
||||
result += ":" + BindingNameGenerator::generate(index) + ", ";
|
||||
result = result.substr(0, result.length() - 2) + ");";
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string table_name{};
|
||||
const std::array<std::string, sizeof...(ColTypes)> columns{};
|
||||
};
|
||||
|
||||
template <typename... ColTypes>
|
||||
struct InsertQuery : public InsertQueryGenerator<ColTypes...> {
|
||||
struct ExecuteResult {
|
||||
std::vector<std::tuple<size_t, sql::result>> failed_entries{};
|
||||
|
||||
[[nodiscard]] inline auto has_succeeded() const { return this->failed_entries.empty(); }
|
||||
};
|
||||
|
||||
explicit InsertQuery(const std::string& target_table, Column<ColTypes>... columns) : InsertQueryGenerator<ColTypes...>{target_table, std::move(columns)...} { }
|
||||
|
||||
inline void reserve_entries(size_t amount) {
|
||||
this->entries.reserve(amount);
|
||||
}
|
||||
|
||||
inline void add_entry(const ColTypes&... values) {
|
||||
this->entries.push_back(std::array<variable, sizeof...(ColTypes)>{variable{"", values}...});
|
||||
}
|
||||
|
||||
inline ExecuteResult execute(sql::SqlManager* sql, bool ignore_fails = false) {
|
||||
if(this->entries.empty()) return ExecuteResult{};
|
||||
|
||||
ExecuteResult result{};
|
||||
|
||||
const auto chunk_size = std::min(2UL, this->entries.size());
|
||||
sql::model chunk_base{sql, this->generate_query(chunk_size, sql->getType(), ignore_fails)};
|
||||
sql::model entry_model{sql, this->generate_query(1, sql->getType(), ignore_fails)};
|
||||
|
||||
for(size_t chunk{0}; chunk < this->entries.size() / chunk_size; chunk++) {
|
||||
auto command = chunk_base.command();
|
||||
size_t parameter_index{1};
|
||||
for(size_t index{chunk * chunk_size}; index < (chunk + 1) * chunk_size; index++) {
|
||||
for(auto& var : this->entries[index]) {
|
||||
var.set_key(":" + BindingNameGenerator::generate(parameter_index++));
|
||||
command.value(var);
|
||||
}
|
||||
}
|
||||
|
||||
auto exec_result = command.execute();
|
||||
if(!exec_result) {
|
||||
/* try every entry 'till we've found the error one */
|
||||
for(size_t index{chunk * chunk_size}; index < (chunk + 1) * chunk_size; index++) {
|
||||
parameter_index = 1;
|
||||
|
||||
auto entry_command = entry_model.command();
|
||||
for(auto& var : this->entries[index]) {
|
||||
var.set_key(":" + BindingNameGenerator::generate(parameter_index++));
|
||||
entry_command.value(var);
|
||||
}
|
||||
exec_result = entry_command.execute();
|
||||
if(!exec_result) {
|
||||
result.failed_entries.emplace_back(index, std::move(exec_result));
|
||||
if(!ignore_fails)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t index{(this->entries.size() / chunk_size) * chunk_size}; index < this->entries.size(); index++) {
|
||||
size_t parameter_index{1};
|
||||
auto entry_command = entry_model.command();
|
||||
for(auto& var : this->entries[index]) {
|
||||
var.set_key(":" + BindingNameGenerator::generate(parameter_index++));
|
||||
entry_command.value(var);
|
||||
}
|
||||
auto exec_result = entry_command.execute();
|
||||
if(!exec_result) {
|
||||
result.failed_entries.emplace_back(index, std::move(exec_result));
|
||||
if(!ignore_fails)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::array<variable, sizeof...(ColTypes)>> entries{};
|
||||
};
|
||||
|
||||
}
|
@ -20,7 +20,6 @@ using namespace sql::mysql;
|
||||
|
||||
MySQLManager::MySQLManager() : SqlManager(SqlType::TYPE_MYSQL) {}
|
||||
MySQLManager::~MySQLManager() {}
|
||||
|
||||
//Property info: https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html
|
||||
//mysql://[host][:port]/[database][?propertyName1=propertyValue1[&propertyName2=propertyValue2]...]
|
||||
|
||||
@ -50,7 +49,7 @@ inline result parse_url(const string& url, std::map<std::string, std::string>& c
|
||||
index = idx + 1;
|
||||
} while(index != 0);
|
||||
}
|
||||
|
||||
//TODO: Set CLIENT_MULTI_STATEMENTS
|
||||
//if(!connect_map["hostName"].get<const char*>() || strcmp(*connect_map["hostName"].get<const char*>(), ""))
|
||||
connect_map["hostName"] = target_url;
|
||||
logTrace(LOG_GENERAL, "Got mysql property {}. Value: {}", "hostName", target_url);
|
||||
|
@ -54,32 +54,30 @@ std::shared_ptr<CommandData> SqliteManager::copyCommandData(std::shared_ptr<Comm
|
||||
return __new;
|
||||
}
|
||||
|
||||
namespace sql {
|
||||
namespace sqlite {
|
||||
inline void bindVariable(sqlite3_stmt* stmt, int& valueIndex, const variable& val){
|
||||
valueIndex = sqlite3_bind_parameter_index(stmt, val.key().c_str());
|
||||
if(valueIndex == 0){ //TODO maybe throw an exception
|
||||
//cerr << "Cant find variable '" + val.key() + "' -> '" + val.value() + "' in query '" + sqlite3_sql(stmt) + "'" << endl;
|
||||
return;
|
||||
}
|
||||
namespace sql::sqlite {
|
||||
inline void bindVariable(sqlite3_stmt* stmt, int& valueIndex, const variable& val){
|
||||
valueIndex = sqlite3_bind_parameter_index(stmt, val.key().c_str());
|
||||
if(valueIndex == 0){ //TODO maybe throw an exception
|
||||
//cerr << "Cant find variable '" + val.key() + "' -> '" + val.value() + "' in query '" + sqlite3_sql(stmt) + "'" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int resultState = 0;
|
||||
if(val.type() == VARTYPE_NULL)
|
||||
resultState = sqlite3_bind_null(stmt, valueIndex);
|
||||
else if(val.type() == VARTYPE_TEXT)
|
||||
resultState = sqlite3_bind_text(stmt, valueIndex, val.value().c_str(), val.value().length(), SQLITE_TRANSIENT);
|
||||
else if(val.type() == VARTYPE_INT || val.type() == VARTYPE_BOOLEAN)
|
||||
resultState = sqlite3_bind_int(stmt, valueIndex, val.as<int32_t>());
|
||||
else if(val.type() == VARTYPE_LONG)
|
||||
resultState = sqlite3_bind_int64(stmt, valueIndex, val.as<int64_t>());
|
||||
else if(val.type() == VARTYPE_DOUBLE || val.type() == VARTYPE_FLOAT)
|
||||
resultState = sqlite3_bind_double(stmt, valueIndex, val.as<double>());
|
||||
else cerr << "Invalid value type!" << endl; //TODO throw exception
|
||||
int resultState = 0;
|
||||
if(val.type() == VARTYPE_NULL)
|
||||
resultState = sqlite3_bind_null(stmt, valueIndex);
|
||||
else if(val.type() == VARTYPE_TEXT)
|
||||
resultState = sqlite3_bind_text(stmt, valueIndex, val.value().c_str(), val.value().length(), SQLITE_TRANSIENT);
|
||||
else if(val.type() == VARTYPE_INT || val.type() == VARTYPE_BOOLEAN)
|
||||
resultState = sqlite3_bind_int(stmt, valueIndex, val.as<int32_t>());
|
||||
else if(val.type() == VARTYPE_LONG)
|
||||
resultState = sqlite3_bind_int64(stmt, valueIndex, val.as<int64_t>());
|
||||
else if(val.type() == VARTYPE_DOUBLE || val.type() == VARTYPE_FLOAT)
|
||||
resultState = sqlite3_bind_double(stmt, valueIndex, val.as<double>());
|
||||
else cerr << "Invalid value type!" << endl; //TODO throw exception
|
||||
|
||||
if(resultState != SQLITE_OK){
|
||||
cerr << "Invalid bind. " << sqlite3_errmsg(sqlite3_db_handle(stmt)) << " Index: " << valueIndex << endl; //TODO throw exception
|
||||
}
|
||||
if(resultState != SQLITE_OK){
|
||||
cerr << "Invalid bind. " << sqlite3_errmsg(sqlite3_db_handle(stmt)) << " Index: " << valueIndex << endl; //TODO throw exception
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,6 +160,8 @@ result SqliteManager::executeCommand(std::shared_ptr<CommandData> _ptr) {
|
||||
bindVariable(stmt, varIndex, var);
|
||||
|
||||
int result = sqlite3_step(stmt);
|
||||
|
||||
//logCritical(0, "Changes: {} SQL: {}", sqlite3_changes(this->database), ptr->sql_command);
|
||||
if(result == SQLITE_DONE)
|
||||
return {_ptr->sql_command,0, "success"};
|
||||
if(result == SQLITE_ROW) return {_ptr->sql_command,-1, "query has a result"};
|
||||
|
@ -132,10 +132,12 @@ int main() {
|
||||
ts::command cmd("notify");
|
||||
*/
|
||||
|
||||
auto command = ts::command_parser{"a a=c a=c2 -z |-? a=2 key_c=c"};
|
||||
auto command = ts::command_parser{"a a=x |x b=x | c=x | a=x"};
|
||||
if(!command.parse(true)) return 1;
|
||||
|
||||
print_entries(command);
|
||||
auto next = command.next_bulk_containing("a", 0);
|
||||
std::cout << (next.has_value() ? *next : -1) << "\n";
|
||||
|
||||
return 0;
|
||||
std::cout << "Command v3:\n";
|
||||
|
222
test/PacketLossCalculateTest.cpp
Normal file
222
test/PacketLossCalculateTest.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// Created by WolverinDEV on 06/04/2020.
|
||||
//
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
#include <src/protocol/PacketLossCalculator.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
using UnorderedPacketLossCalculator = ts::protocol::UnorderedPacketLossCalculator;
|
||||
|
||||
inline void print_unordered_stats(UnorderedPacketLossCalculator& generator) {
|
||||
std::cout << "Valid data: " << generator.valid_data() << ". (Received{local: " << generator.received_packets() << ", unconfirmed: " << generator.unconfirmed_received_packets() << ", total: " << generator.received_packets_total() << "}" <<
|
||||
" Lost: {local: " << generator.lost_packets() << ", unconfirmed: " << generator.unconfirmed_lost_packets() << ", total: " << generator.lost_packets_total() << "} Current ID: " << generator.last_packet_id() << ")\n";
|
||||
}
|
||||
|
||||
template <typename vector_t>
|
||||
vector_t swap_elements(vector_t vector, int per, int max_distance) {
|
||||
for(size_t index = 0; index < vector.size() - max_distance; index++) {
|
||||
if ((rand() % 100) < per) {
|
||||
//lets switch
|
||||
auto offset = rand() % max_distance;
|
||||
std::swap(vector[index], vector[index + offset]);
|
||||
}
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
inline void generate_unordered(UnorderedPacketLossCalculator& generator, int loss, size_t count) {
|
||||
size_t id{generator.last_packet_id()};
|
||||
while(count--) {
|
||||
if(rand() % 100 >= loss)
|
||||
generator.packet_received(id);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
void test_const_unordered_0() {
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
generator.packet_received(pid);
|
||||
|
||||
assert(generator.received_packets_total() == 68);
|
||||
assert(generator.unconfirmed_received_packets() == 32);
|
||||
assert(generator.received_packets() == 68);
|
||||
|
||||
assert(generator.lost_packets_total() == 0);
|
||||
assert(generator.lost_packets() == 0);
|
||||
assert(generator.unconfirmed_lost_packets() == 0);
|
||||
|
||||
assert(generator.valid_data());
|
||||
}
|
||||
|
||||
|
||||
void test_const_unordered_1() {
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
generator.packet_received(100); /* we lost the first 99 packets */
|
||||
|
||||
assert(generator.received_packets_total() == 0);
|
||||
assert(generator.unconfirmed_received_packets() == 1);
|
||||
assert(generator.received_packets() == 0);
|
||||
|
||||
assert(generator.lost_packets_total() == 68);
|
||||
assert(generator.lost_packets() == 68);
|
||||
assert(generator.unconfirmed_lost_packets() == 31);
|
||||
|
||||
assert(generator.valid_data());
|
||||
}
|
||||
|
||||
void test_const_unordered_2() {
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
if(pid % 2)
|
||||
generator.packet_received(pid);
|
||||
|
||||
assert(generator.received_packets_total() == 34);
|
||||
assert(generator.received_packets() == 34);
|
||||
assert(generator.unconfirmed_received_packets() == 16);
|
||||
|
||||
assert(generator.lost_packets_total() == 34);
|
||||
assert(generator.lost_packets() == 34);
|
||||
assert(generator.unconfirmed_lost_packets() == 16);
|
||||
|
||||
assert(generator.valid_data());
|
||||
}
|
||||
|
||||
|
||||
void test_const_unordered_3() {
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
if(pid % 3)
|
||||
generator.packet_received(pid);
|
||||
|
||||
assert(generator.received_packets_total() == 44);
|
||||
assert(generator.received_packets() == 44);
|
||||
assert(generator.unconfirmed_received_packets() == 22);
|
||||
|
||||
assert(generator.lost_packets_total() == 23);
|
||||
assert(generator.lost_packets() == 23);
|
||||
assert(generator.unconfirmed_lost_packets() == 10);
|
||||
|
||||
assert(generator.valid_data());
|
||||
}
|
||||
|
||||
void test_const_unordered_4() {
|
||||
std::vector<uint32_t> received_packets{};
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
received_packets.push_back(pid);
|
||||
|
||||
received_packets = swap_elements(received_packets, 50, 7);
|
||||
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
for(const auto& packet : received_packets)
|
||||
generator.packet_received(packet);
|
||||
|
||||
assert(generator.received_packets_total() == 68);
|
||||
assert(generator.unconfirmed_received_packets() == 32);
|
||||
assert(generator.received_packets() == 68);
|
||||
|
||||
assert(generator.lost_packets_total() == 0);
|
||||
assert(generator.lost_packets() == 0);
|
||||
assert(generator.unconfirmed_lost_packets() == 0);
|
||||
|
||||
assert(generator.valid_data());
|
||||
}
|
||||
|
||||
void test_const_unordered_5() {
|
||||
std::vector<uint32_t> received_packets{};
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
if(pid % 3)
|
||||
received_packets.push_back(pid);
|
||||
|
||||
received_packets = swap_elements(received_packets, 30, 7);
|
||||
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
for(const auto& packet : received_packets)
|
||||
generator.packet_received(packet);
|
||||
|
||||
assert(generator.received_packets_total() == 44);
|
||||
assert(generator.received_packets() == 44);
|
||||
assert(generator.unconfirmed_received_packets() == 22);
|
||||
|
||||
assert(generator.lost_packets_total() == 23);
|
||||
assert(generator.lost_packets() == 23);
|
||||
assert(generator.unconfirmed_lost_packets() == 10);
|
||||
|
||||
assert(generator.valid_data());
|
||||
}
|
||||
|
||||
void test_unordered_6() {
|
||||
UnorderedPacketLossCalculator generator{};
|
||||
{
|
||||
const auto pid_base = generator.last_packet_id();
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
generator.packet_received(pid_base + pid);
|
||||
}
|
||||
|
||||
print_unordered_stats(generator);
|
||||
generator.short_stats();
|
||||
|
||||
{
|
||||
const auto pid_base = generator.last_packet_id();
|
||||
generator.packet_received(pid_base + 100);
|
||||
}
|
||||
print_unordered_stats(generator);
|
||||
generator.short_stats();
|
||||
|
||||
{
|
||||
const auto pid_base = generator.last_packet_id();
|
||||
generator.packet_received(pid_base + 100);
|
||||
}
|
||||
print_unordered_stats(generator);
|
||||
generator.short_stats();
|
||||
{
|
||||
const auto pid_base = generator.last_packet_id();
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
generator.packet_received(pid_base + pid);
|
||||
}
|
||||
print_unordered_stats(generator);
|
||||
generator.short_stats();
|
||||
{
|
||||
const auto pid_base = generator.last_packet_id();
|
||||
for(size_t pid{0}; pid < 100; pid++)
|
||||
generator.packet_received(pid_base + pid);
|
||||
}
|
||||
print_unordered_stats(generator);
|
||||
}
|
||||
|
||||
int main() {
|
||||
#if 0
|
||||
test_const_unordered_0();
|
||||
test_const_unordered_1();
|
||||
test_const_unordered_2();
|
||||
test_const_unordered_3();
|
||||
test_const_unordered_4();
|
||||
test_const_unordered_5();
|
||||
test_unordered_6();
|
||||
#endif
|
||||
size_t value = 0;
|
||||
|
||||
|
||||
std::vector<size_t> bandwidth_seconds{};
|
||||
for(size_t iteration{0}; iteration < 600; iteration++) {
|
||||
if(iteration >= 200 && iteration <= 270)
|
||||
bandwidth_seconds.push_back(0);
|
||||
else
|
||||
bandwidth_seconds.push_back(500);
|
||||
}
|
||||
|
||||
constexpr auto cofactor = 0.915;
|
||||
//constexpr auto cofactor = 0.978;
|
||||
for(size_t iteration{0}; iteration < bandwidth_seconds.size(); iteration++) {
|
||||
const auto next_value = value * cofactor + bandwidth_seconds[iteration] * (1 - cofactor);
|
||||
if(next_value > value)
|
||||
value = ceil(next_value);
|
||||
else
|
||||
value = floor(next_value);
|
||||
std::cout << iteration << ": " << value << "\n";
|
||||
}
|
||||
}
|
@ -7,15 +7,14 @@ using namespace std;
|
||||
|
||||
|
||||
int main() {
|
||||
assert(property::impl::validateUnique());
|
||||
//assert(property::impl::validateUnique());
|
||||
|
||||
cout << property::impl::info(property::VIRTUALSERVER_HOST)->name << endl;
|
||||
cout << property::impl::info<property::VirtualServerProperties>("virtualserver_host")->name<< endl;
|
||||
cout << property::describe(property::VIRTUALSERVER_HOST).name << endl;
|
||||
cout << property::find(property::PROP_TYPE_SERVER, "virtualserver_host").name<< endl;
|
||||
|
||||
Properties props;
|
||||
props.register_property_type<property::InstanceProperties>();
|
||||
|
||||
cout << "X: " << property::impl::info(property::SERVERINSTANCE_QUERY_PORT)->default_value << endl;
|
||||
auto property = props[property::SERVERINSTANCE_QUERY_PORT];
|
||||
|
||||
cout << "Port: " << props[property::SERVERINSTANCE_QUERY_PORT].as<string>() << endl;
|
||||
@ -26,6 +25,7 @@ int main() {
|
||||
cout << "Port: " << props[property::SERVERINSTANCE_QUERY_PORT].as<int32_t>() << endl;
|
||||
|
||||
|
||||
/*
|
||||
{
|
||||
assert(property::impl::validateInput("022222", property::TYPE_UNSIGNED_NUMBER) == true);
|
||||
assert(property::impl::validateInput("000000", property::TYPE_UNSIGNED_NUMBER) == true);
|
||||
@ -54,6 +54,7 @@ int main() {
|
||||
assert(property::impl::validateInput("-.1-", property::TYPE_FLOAT) == false);
|
||||
assert(property::impl::validateInput("-2.22222.2", property::TYPE_FLOAT) == false);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
TIMING_START(timings);
|
||||
|
200
test/SQL2Test.cpp
Normal file
200
test/SQL2Test.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <sql/SqlQuery.h>
|
||||
|
||||
#if 0
|
||||
template <typename T>
|
||||
struct Column {
|
||||
constexpr explicit Column(const std::string_view& name) : name{name} { }
|
||||
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
struct BindingNameGenerator {
|
||||
public:
|
||||
[[nodiscard]] static std::string generate(size_t index) {
|
||||
assert(index > 0);
|
||||
std::string result{};
|
||||
result.resize(std::max(index >> 4U, 1UL));
|
||||
for(auto it = result.begin(); index > 0; index >>= 4U)
|
||||
*(it++) = number_map[index & 0xFU];
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static std::array<char, 16> number_map{
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p'
|
||||
};
|
||||
};
|
||||
|
||||
template <typename... ColTypes>
|
||||
struct InsertQueryGenerator {
|
||||
struct GenerateOptions {
|
||||
bool enable_ignore{false};
|
||||
sql::SqlType target{sql::SqlType::TYPE_SQLITE};
|
||||
};
|
||||
|
||||
explicit InsertQueryGenerator(std::string target_table, Column<ColTypes>... columns) : table_name{std::move(target_table)}, columns{std::move(columns.name)...} { }
|
||||
|
||||
[[nodiscard]] constexpr inline auto column_count() const { return sizeof...(ColTypes); };
|
||||
|
||||
[[nodiscard]] inline std::string generate_query(size_t entry_count, sql::SqlType target = sql::SqlType::TYPE_SQLITE, bool enable_ignore = false) const {
|
||||
if(entry_count == 0) return "-- No entries given";
|
||||
|
||||
std::string result{"INSERT "};
|
||||
if(enable_ignore) {
|
||||
if(target == sql::TYPE_MYSQL)
|
||||
result += "IGNORE ";
|
||||
else
|
||||
result += "OR IGNORE ";
|
||||
}
|
||||
|
||||
result += this->table_name + " (";
|
||||
//"INSERT INTO " + this->table_name + " ("
|
||||
for(auto it = this->columns.begin();;) {
|
||||
result += "`" + *it + "`";
|
||||
if(++it != this->columns.end()) {
|
||||
result += ", ";
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result += ") VALUES (";
|
||||
for(size_t index{1}; index <= this->column_count() * entry_count; index++)
|
||||
result += ":" + BindingNameGenerator::generate(index) + ", ";
|
||||
result = result.substr(0, result.length() - 2) + ");";
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string table_name{};
|
||||
const std::array<std::string, sizeof...(ColTypes)> columns{};
|
||||
};
|
||||
|
||||
template <typename... ColTypes>
|
||||
struct InsertQuery : public InsertQueryGenerator<ColTypes...> {
|
||||
struct ExecuteResult {
|
||||
std::vector<std::tuple<size_t, sql::result>> failed_entries{};
|
||||
|
||||
[[nodiscard]] inline auto has_succeeded() const { return this->failed_entries.empty(); }
|
||||
};
|
||||
|
||||
explicit InsertQuery(const std::string& target_table, Column<ColTypes>... columns) : InsertQueryGenerator<ColTypes...>{target_table, std::move(columns)...} { }
|
||||
|
||||
inline void reserve_entries(size_t amount) {
|
||||
this->entries.reserve(amount);
|
||||
}
|
||||
|
||||
inline void add_entry(const ColTypes&... values) {
|
||||
this->entries.push_back(std::array<variable, sizeof...(ColTypes)>{variable{"", values}...});
|
||||
}
|
||||
|
||||
inline ExecuteResult execute(sql::SqlManager* sql, bool ignore_fails = false) {
|
||||
if(this->entries.empty()) return ExecuteResult{};
|
||||
|
||||
ExecuteResult result{};
|
||||
|
||||
const auto chunk_size = std::min(2UL, this->entries.size());
|
||||
sql::model chunk_base{sql, this->generate_query(chunk_size, sql->getType(), ignore_fails)};
|
||||
sql::model entry_model{sql, this->generate_query(1, sql->getType(), ignore_fails)};
|
||||
|
||||
for(size_t chunk{0}; chunk < this->entries.size() / chunk_size; chunk++) {
|
||||
auto command = chunk_base.command();
|
||||
size_t parameter_index{1};
|
||||
for(size_t index{chunk * chunk_size}; index < (chunk + 1) * chunk_size; index++) {
|
||||
for(auto& var : this->entries[index]) {
|
||||
var.set_key(":" + BindingNameGenerator::generate(parameter_index++));
|
||||
command.value(var);
|
||||
}
|
||||
}
|
||||
|
||||
auto exec_result = command.execute();
|
||||
if(!exec_result) {
|
||||
/* try every entry 'till we've found the error one */
|
||||
for(size_t index{chunk * chunk_size}; index < (chunk + 1) * chunk_size; index++) {
|
||||
parameter_index = 1;
|
||||
|
||||
auto entry_command = entry_model.command();
|
||||
for(auto& var : this->entries[index]) {
|
||||
var.set_key(":" + BindingNameGenerator::generate(parameter_index++));
|
||||
entry_command.value(var);
|
||||
}
|
||||
exec_result = entry_command.execute();
|
||||
if(!exec_result) {
|
||||
result.failed_entries.emplace_back(index, std::move(exec_result));
|
||||
if(!ignore_fails)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t index{(this->entries.size() / chunk_size) * chunk_size}; index < this->entries.size(); index++) {
|
||||
size_t parameter_index{1};
|
||||
auto entry_command = entry_model.command();
|
||||
for(auto& var : this->entries[index]) {
|
||||
var.set_key(":" + BindingNameGenerator::generate(parameter_index++));
|
||||
entry_command.value(var);
|
||||
}
|
||||
auto exec_result = entry_command.execute();
|
||||
if(!exec_result) {
|
||||
result.failed_entries.emplace_back(index, std::move(exec_result));
|
||||
if(!ignore_fails)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::array<variable, sizeof...(ColTypes)>> entries{};
|
||||
};
|
||||
|
||||
int main() {
|
||||
InsertQuery insert{"hello", Column<int>{"column_a"}, Column<std::string>{"column_ab"}};
|
||||
|
||||
for(int i{0}; i < 100; i++)
|
||||
insert.add_entry(i, "X");
|
||||
|
||||
std::cout << "Result: " << insert.generate_query(2) << "\n";
|
||||
|
||||
std::string value{};
|
||||
insert.add_entry(2, value);
|
||||
insert.execute(nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct A {
|
||||
A() {}
|
||||
~A() = default;
|
||||
};
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <src/misc/net.h>
|
||||
|
||||
int main() {
|
||||
#if 0
|
||||
std::set<int> elements{};
|
||||
if(!elements.empty()) {
|
||||
auto it = elements.begin();
|
||||
const int* last_element{&*(it++)}; /* if elements would be empty this would be undefined behaviour */
|
||||
while(it != elements.end()) {
|
||||
const auto now = *it++;
|
||||
const auto diff = last_element - now;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sockaddr_in addr{};
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(9987);
|
||||
|
||||
std::cout << "Result: " << (int) net::address_available(*(sockaddr_storage*) &addr, net::binding_type::TCP) << "\n";
|
||||
std::cout << strerror(errno) << "\n";
|
||||
}
|
@ -8,14 +8,14 @@ using namespace ts::protocol;
|
||||
|
||||
typedef std::vector<std::pair<size_t, size_t>> test_vector_t;
|
||||
|
||||
test_vector_t generate_test_vector(size_t size, int loss) {
|
||||
test_vector_t generate_test_vector(size_t size, int loss, int step = 1) {
|
||||
test_vector_t result{};
|
||||
result.reserve(size);
|
||||
|
||||
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
if ((rand() % 100) < loss) continue;
|
||||
result.emplace_back(i & 0xFFFFU, i >> 16U);
|
||||
result.emplace_back((i * step) & 0xFFFFU, (i * step) >> 16U);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -26,8 +26,6 @@ test_vector_t swap_elements(test_vector_t vector, int per, int max_distance) {
|
||||
if ((rand() % 100) < per) {
|
||||
//lets switch
|
||||
auto offset = rand() % max_distance;
|
||||
if(!offset) offset = 1;
|
||||
|
||||
std::swap(vector[index], vector[index + offset]);
|
||||
}
|
||||
}
|
||||
@ -38,13 +36,15 @@ test_vector_t swap_elements(test_vector_t vector, int per, int max_distance) {
|
||||
bool test_vector(const std::string_view& name, const test_vector_t& vector) {
|
||||
generation_estimator gen{};
|
||||
|
||||
size_t last_value{0};
|
||||
size_t last_value{0}, last_gen{0}, index{0};
|
||||
for(auto [id, exp] : vector) {
|
||||
if(auto val = gen.visit_packet(id); val != exp) {
|
||||
std::cout << "[" << name << "] failed for " << id << " -> " << exp << " | " << val << ". Last value: " << last_value << "\n";
|
||||
std::cout << "[" << name << "] failed for " << id << " -> " << exp << " | " << val << ". Last value: " << last_value << " gen: " << last_gen << "\n";
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
last_gen = val;
|
||||
last_value = id;
|
||||
index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -70,36 +70,43 @@ int main() {
|
||||
generation_estimator gen{};
|
||||
|
||||
{
|
||||
test_vector("00 loss", generate_test_vector(0x3000, 0));
|
||||
test_vector("10 loss", generate_test_vector(0x3000, 10));
|
||||
test_vector("25 loss", generate_test_vector(0x3000, 25));
|
||||
test_vector("50 loss", generate_test_vector(0x3000, 50));
|
||||
test_vector("80 loss", generate_test_vector(0x3000, 80));
|
||||
test_vector("00 loss", generate_test_vector(0x30000, 0));
|
||||
test_vector("10 loss", generate_test_vector(0x30000, 10));
|
||||
test_vector("25 loss", generate_test_vector(0x30000, 25));
|
||||
test_vector("50 loss", generate_test_vector(0x30000, 50));
|
||||
test_vector("80 loss", generate_test_vector(0x30000, 80));
|
||||
test_vector("99 loss", generate_test_vector(0x30000, 99));
|
||||
}
|
||||
|
||||
{
|
||||
auto base = generate_test_vector(0x3000, 0);
|
||||
auto base = generate_test_vector(0x30000, 0);
|
||||
test_vector("swap 30:4", swap_elements(base, 30, 4));
|
||||
test_vector("swap 30:20", swap_elements(base, 30, 20));
|
||||
test_vector("swap 30:1000", swap_elements(base, 30, 200));
|
||||
test_vector("swap 80:1000", swap_elements(base, 80, 200));
|
||||
}
|
||||
|
||||
if(false) {
|
||||
test_vector("10 loss", generate_test_vector(0x3000, 10));
|
||||
test_vector("25 loss", generate_test_vector(0x3000, 25));
|
||||
test_vector("50 loss", generate_test_vector(0x3000, 50));
|
||||
test_vector("80 loss", generate_test_vector(0x3000, 80));
|
||||
{
|
||||
test_vector("1k step", swap_elements(generate_test_vector(0x30000, 0, 6), 100, 8));
|
||||
|
||||
}
|
||||
|
||||
gen.set_last_state(0, 0);
|
||||
test_vector<6>(gen, {0, 1, 2, 4, 3, 5}, {0, 0, 0, 0, 0, 0});
|
||||
if(true) {
|
||||
#if 0
|
||||
gen.set_last_state(0, 0);
|
||||
test_vector<6>(gen, {0, 1, 2, 4, 3, 5}, {0, 0, 0, 0, 0, 0});
|
||||
|
||||
gen.set_last_state(0xFF00, 0);
|
||||
test_vector<6>(gen, {0, 1, 2, 4, 3, 5}, {1, 1, 1, 1, 1, 1});
|
||||
gen.set_last_state(0xFF00, 0);
|
||||
test_vector<6>(gen, {0, 1, 2, 4, 3, 5}, {1, 1, 1, 1, 1, 1});
|
||||
|
||||
gen.set_last_state(0xFF00, 0);
|
||||
test_vector<6>(gen, {0, 1, 2, 0xFF00, 3, 5}, {1, 1, 1, 0, 1, 1});
|
||||
gen.set_last_state(0xFF00, 0);
|
||||
test_vector<6>(gen, {0, 1, 2, 0xFF00, 3, 5}, {1, 1, 1, 0, 1, 1});
|
||||
|
||||
gen.set_last_state(0xFF00, 0);
|
||||
test_vector<6>(gen, {0xFFFE, 0xFFFF, 0, 1, 0xFFFC, 2}, {0, 0, 1, 1, 0, 1});
|
||||
gen.set_last_state(0xFF00, 0);
|
||||
test_vector<6>(gen, {0xFFFE, 0xFFFF, 0, 1, 0xFFFC, 2}, {0, 0, 1, 1, 0, 1});
|
||||
#endif
|
||||
|
||||
gen.set_last_state(0xFF00, 1);
|
||||
test_vector<6>(gen, {0xFFFE, 0xFFFF, 0, 1, 0xFFFC, 2}, {1, 1, 2, 2, 1, 2});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user