Using new command error system

This commit is contained in:
WolverinDEV 2020-01-25 23:42:36 +01:00
parent 664b73910c
commit d42ec40a58
16 changed files with 704 additions and 959 deletions

View File

@ -95,6 +95,9 @@ set(SOURCE_FILES
src/qlz/QuickLZ_L3.cpp
src/qlz/QuickLZ_L1.cpp
src/converters/converter.cpp
src/query/command3.cpp
src/query/command2.cpp
src/query/Command.cpp
src/query/escape.cpp
@ -228,6 +231,7 @@ set(TEST_LIBRARIES
jsoncpp_lib
${ed25519_LIBRARIES_STATIC}
${DataPipes_LIBRARIES_SHARED}
ffi
openssl::ssl::shared
openssl::crypto::shared
dl
@ -262,7 +266,7 @@ if(BUILD_TESTS)
add_executable(PorpertyTest test/PropertyTest.cpp ${SOURCE_FILES})
target_link_libraries(PorpertyTest ${TEST_LIBRARIES})
add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES})
add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES} src/query/command_unused.h src/converters/converter.cpp src/query/command_handler.h)
target_link_libraries(BBTest ${TEST_LIBRARIES})
add_executable(LinkedTest test/LinkedTest.cpp ${SOURCE_FILES})

View File

@ -34,6 +34,9 @@ const std::vector<ErrorType> ts::avariableErrors = {
{0x020F, "client_login_not_permitted" , "client is not permitted to log in" },
{0x0210, "client_not_subscribed" , "client is not subscribed to the channel" },
{0x0211, "client_unknown" , "client is not known" },
{0x0212, "client_join_rate_limit_reached" , "client has reached his join attempt limit" },
{0x0213, "client_is_already_member_of_group" , "client is already a member of the group" },
{0x0213, "client_is_not_member_of_group" , "client is not a member of the group" },
{0x0300, "channel_invalid_id" , "invalid channelID" },
{0x0301, "channel_protocol_limit_reached" , "max channels protocol limit reached" },
@ -52,6 +55,7 @@ const std::vector<ErrorType> ts::avariableErrors = {
{0x030E, "channel_is_private_channel" , "channel is private channel" },
{0x030F, "channel_invalid_security_hash" , "invalid security hash supplied by client" },
{0x0310, "channel_is_deleted" , "target channel is deleted" },
{0x0311, "channel_name_invalid" , "channel name is invalid" },
{0x0400, "server_invalid_id" , "invalid serverID" },
{0x0401, "server_running" , "server is running" },
@ -70,6 +74,9 @@ const std::vector<ErrorType> ts::avariableErrors = {
{0x040D, "server_already_joined" , "query client already joined to the server" },
{0x040E, "server_is_not_shutting_down" , "server isn't shutting down" },
{0x040F, "server_max_vs_reached" , "You reached the maximal virtual server limit" },
{0x0410, "server_unbound" , "you are not bound to any server" },
{0x0411, "server_join_rate_limit_reached" , "the server reached his join attempt limit" },
{0x0500, "sql" , "sql error" },
{0x0501, "database_empty_result" , "sql empty result set" },
@ -139,7 +146,8 @@ const std::vector<ErrorType> ts::avariableErrors = {
{0x1001, "web_handshake_invalid" , "Invalid handshake" },
{0x1001, "web_handshake_unsupported" , "Handshake intention unsupported" },
{0x1002, "web_handshake_identity_unsupported" , "Handshake identity unsupported" },
{0x1002, "web_handshake_identity_proof_failed" , "Identity proof failed" },
{0x1003, "web_handshake_identity_proof_failed" , "Identity proof failed" },
{0x1004, "web_handshake_identity_outdated" , "data seems to be outdated" },
{0x1100, "music_invalid_id" , "invalid botID" },
{0x1101, "music_limit_reached" , "Server music bot limit is reached" },
@ -165,6 +173,7 @@ const std::vector<ErrorType> ts::avariableErrors = {
{0x1300, "group_invalid_id" , "Invalid group id" },
{0x1301, "group_name_inuse" , "Group name is already in use" },
{0x1302, "group_not_assigned_over_this_server" , "the group hasn't been assigned over this server" },
{0xE000, "resource_limit_reached" , "resource limit reached" },

View File

@ -30,6 +30,7 @@ namespace ts {
client_invalid_id = 0x200,
client_nickname_inuse = 0x201,
invalid_error_code = 0x202,
client_protocol_limit_reached = 0x203,
client_invalid_type = 0x204,
client_already_subscribed = 0x205,
@ -44,6 +45,11 @@ namespace ts {
client_cannot_verify_now = 0x20e,
client_login_not_permitted = 0x20f,
client_not_subscribed = 0x210,
client_unknown = 0x0211,
client_join_rate_limit_reached = 0x0212,
client_is_already_member_of_group = 0x0213,
client_is_not_member_of_group = 0x0214,
channel_invalid_id = 0x300,
channel_protocol_limit_reached = 0x301,
channel_already_in = 0x302,
@ -61,6 +67,8 @@ namespace ts {
channel_is_private_channel = 0x30e,
channel_invalid_security_hash = 0x30f,
channel_is_deleted = 0x310,
channel_name_invalid = 0x311,
server_invalid_id = 0x400,
server_running = 0x401,
server_is_shutting_down = 0x402,
@ -77,6 +85,10 @@ namespace ts {
server_version_outdated = 0x40d,
server_already_joined = 0x40d,
server_is_not_shutting_down = 0x40e,
server_max_vs_reached = 0x40f,
server_unbound = 0x410,
server_join_rate_limit_reached = 0x411,
sql = 0x500,
database_empty_result = 0x501,
database_duplicate_entry = 0x502,
@ -136,7 +148,9 @@ namespace ts {
web_handshake_invalid = 0x1001,
web_handshake_unsupported = 0x1001,
web_handshake_identity_unsupported = 0x1002,
web_handshake_identity_proof_failed = 0x1002,
web_handshake_identity_proof_failed = 0x1003,
web_handshake_identity_outdated = 0x1004,
music_invalid_id = 0x1100,
music_limit_reached = 0x1101,
music_client_limit_reached = 0x1102,
@ -150,6 +164,15 @@ namespace ts {
playlist_is_in_use = 0x2103,
query_not_exists = 0x1200,
query_already_exists = 0x1201,
group_invalid_id = 0x1300,
group_name_inuse = 0x1301,
group_not_assigned_over_this_server = 0x1302,
conversation_invalid_id = 0x2200,
conversation_more_data = 0x2201,
conversation_is_private = 0x2202,
custom_error = 0xffff
};
};
@ -186,10 +209,18 @@ namespace ts {
static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62);
[[nodiscard]] inline error::type error_code() const {
if(this->is_detailed()) return this->details()->error_id;
return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR);
}
[[nodiscard]] inline bool is_permission_error() const {
return this->error_code() == error::server_insufficeient_permissions;
}
[[nodiscard]] inline permission::PermissionType permission_id() const {
if(this->is_detailed()) return (permission::PermissionType) -1; /* not supported */
return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION);
}
@ -201,6 +232,8 @@ namespace ts {
}
inline std::unique_ptr<detailed_command_result> release_details() {
if(!this->is_detailed()) return nullptr;
auto result = this->details();
this->data = 0;
return std::unique_ptr<detailed_command_result>{result};

View File

@ -0,0 +1,40 @@
#include "converter.h"
#include <sstream>
#include <algorithm>
using namespace std;
using namespace ts;
#define CONVERTER_ST(type, m_decode, m_encode) \
CONVERTER_METHOD_DECODE(type, impl::converter_ ##type ##_decode) { \
m_decode; \
} \
\
CONVERTER_METHOD_ENCODE(type, impl::converter_ ##type ##_encode) { \
m_encode \
}
#define CONVERTER_PRIMITIVE_ST(type, m_decode) CONVERTER_ST(type, \
return m_decode;, \
return std::to_string(std::any_cast<type>(value)); \
)
CONVERTER_PRIMITIVE_ST(int8_t, std::stol(std::string{str}) & 0xFF);
CONVERTER_PRIMITIVE_ST(uint8_t, std::stoul(std::string{str}) & 0xFF);
CONVERTER_PRIMITIVE_ST(int16_t, std::stol(std::string{str}) & 0xFFFF);
CONVERTER_PRIMITIVE_ST(uint16_t, std::stoul(std::string{str}) & 0xFFFF);
CONVERTER_PRIMITIVE_ST(int32_t, std::stol(std::string{str}) & 0xFFFFFFFF);
CONVERTER_PRIMITIVE_ST(uint32_t, std::stoul(std::string{str}) & 0xFFFFFFFF);
CONVERTER_PRIMITIVE_ST(int64_t, std::stoll(std::string{str}));
CONVERTER_PRIMITIVE_ST(uint64_t, std::stoull(std::string{str}))
CONVERTER_PRIMITIVE_ST(bool, str == "1" || str == "true");
CONVERTER_PRIMITIVE_ST(float, std::stof(std::string{str}));
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)););

View File

@ -1,6 +1,8 @@
#pragma once
#include <any>
#include <string>
#include <cstddef>
namespace ts {
typedef long double long_double;
@ -20,10 +22,10 @@ namespace ts {
static constexpr bool supported = true; \
\
static constexpr std::string(*to_string)(const std::any&) = encode; \
static constexpr type(*from_string)(const std::string&) = decode; \
static constexpr type(*from_string)(const std::string_view&) = decode; \
};
#define CONVERTER_METHOD_DECODE(type, name) type name(const std::string& str)
#define CONVERTER_METHOD_DECODE(type, name) type name(const std::string_view& str)
#define CONVERTER_METHOD_ENCODE(type, name) std::string name(const std::any& value)
/* helper for primitive types */

View File

@ -1,11 +1,12 @@
#include "Command.h"
#include "command_exception.h"
#include <sstream>
#include <iostream>
#include <algorithm>
#include <pipes/buffer.h>
#include "log/LogUtils.h"
#include "escape.h"
#include "command2.h"
using namespace std;

View File

@ -1,4 +1,3 @@
#include "command2.h"
#include "escape.h"
#include <sstream>
#include <algorithm>
@ -6,178 +5,7 @@
using namespace std;
using namespace ts;
#define CONVERTER_ST(type, m_decode, m_encode) \
CONVERTER_METHOD_DECODE(type, impl::converter_ ##type ##_decode) { \
m_decode; \
} \
\
CONVERTER_METHOD_ENCODE(type, impl::converter_ ##type ##_encode) { \
m_encode \
}
#define CONVERTER_PRIMITIVE_ST(type, m_decode) CONVERTER_ST(type, \
return m_decode;, \
return std::to_string(std::any_cast<type>(value)); \
)
CONVERTER_PRIMITIVE_ST(int8_t, std::stol(str) & 0xFF);
CONVERTER_PRIMITIVE_ST(uint8_t, std::stoul(str) & 0xFF);
CONVERTER_PRIMITIVE_ST(int16_t, std::stol(str) & 0xFFFF);
CONVERTER_PRIMITIVE_ST(uint16_t, std::stoul(str) & 0xFFFF);
CONVERTER_PRIMITIVE_ST(int32_t, std::stol(str) & 0xFFFFFFFF);
CONVERTER_PRIMITIVE_ST(uint32_t, std::stoul(str) & 0xFFFFFFFF);
CONVERTER_PRIMITIVE_ST(int64_t, std::stoll(str));
CONVERTER_PRIMITIVE_ST(uint64_t, std::stoull(str))
CONVERTER_PRIMITIVE_ST(bool, str == "1" || str == "true");
CONVERTER_PRIMITIVE_ST(float, std::stof(str));
CONVERTER_PRIMITIVE_ST(double, std::stod(str));
CONVERTER_PRIMITIVE_ST(long_double, std::stold(str));
CONVERTER_ST(std__string, return str;, return std::any_cast<std__string>(value););
CONVERTER_ST(const_char__ , return str.c_str();, return std::string(std::any_cast<const_char__>(value)););
command::command(const std::string& command, bool editable) {
this->handle = make_shared<impl::command_data>();
this->handle->editable = editable;
this->handle->command = command;
}
const std::string& command::identifier() const {
return this->handle->command;
}
void command::set_identifier(const std::string &command) {
this->handle->command = command;
}
command_bulk command::bulk(size_t index) {
if(this->handle->bulks.size() <= index) {
if(!this->handle->editable)
throw command_bulk_exceed_index_exception();
while(this->handle->bulks.size() <= index) {
auto bulk = make_shared<impl::command_bulk>();
bulk->handle = this->handle.get();
this->handle->bulks.push_back(std::move(bulk));
}
}
return {index, this->handle->bulks[index]};
}
const command_bulk command::bulk(size_t index) const {
if(this->handle->bulks.size() <= index)
throw command_bulk_exceed_index_exception();
return {index, this->handle->bulks[index]};
}
size_t command::bulk_count() const {
return this->handle->bulks.size();
}
command_entry command::value(const std::string &key) {
return this->bulk(0)[key];
}
const command_entry command::value(const std::string &key) const {
return this->bulk(0)[key];
}
bool command::has_value(const std::string &key) const {
if(this->bulk_count() == 0) return false;
return this->bulk(0).has(key);
}
bool command::has_trigger(const std::string &key) const {
for(const auto& trigger : this->handle->triggers)
if(trigger == key)
return true;
return false;
}
void command::set_trigger(const std::string &key, bool value) {
auto& triggers = this->handle->triggers;
auto it = find(triggers.begin(), triggers.end(), key);
if(it == triggers.end() && value) {
triggers.push_back(key);
} else if(it != triggers.end() && !value) {
triggers.erase(it);
}
}
command command::parse(const std::string_view &data, bool expect_type, bool drop_non_utf8) {
command result;
size_t current_index = std::string::npos, end_index;
if(expect_type) {
current_index = data.find(' ', 0);
if(current_index == std::string::npos){
result.set_identifier(std::string(data));
return result;
} else {
result.set_identifier(std::string(data.substr(0, current_index)));
}
}
size_t bulk_index = 0;
while(++current_index > 0 || (current_index == 0 && !expect_type)) {
expect_type = true;
end_index = data.find_first_of(" |", current_index);
if(end_index != current_index) { /* else we've found another space or a pipe */
if(data[current_index] == '-') {
string trigger(data.substr(current_index + 1, end_index - current_index - 1));
result.set_trigger(trigger);
} else {
auto index_assign = data.find_first_of('=', current_index);
string key, value;
if(index_assign == string::npos || index_assign > end_index) {
key = data.substr(current_index, end_index - current_index);
} else {
key = data.substr(current_index, index_assign - current_index);
try {
value = query::unescape(string(data.substr(index_assign + 1, end_index - index_assign - 1)), true);
} catch(const std::invalid_argument& ex) {
(void) ex;
/* invalid character at index X */
if(!drop_non_utf8)
throw;
goto skip_assign;
}
}
{
const static auto key_validator = [](char c){ return !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-'); };
auto invalid_index = find_if(key.begin(), key.end(), key_validator);
if(invalid_index != key.end())
throw command_malformed_exception(current_index + distance(key.begin(), invalid_index));
if(!key.empty() && !result[bulk_index].has(key))
result[bulk_index][key] = value;
}
skip_assign:;
}
}
if(end_index < data.length() && data[end_index] == '|')
bulk_index++;
current_index = end_index;
}
return result;
}
/*
std::string command::build(ts::command::format::value type) {
if(type == format::QUERY || type == format::BRACE_ESCAPED_QUERY) {
std::stringstream ss;
@ -223,34 +51,4 @@ std::string command::build(ts::command::format::value type) {
}
return "";
}
bool command_bulk::has(const std::string &key) const {
auto& values = this->handle->values;
auto index = values.find(key);
return index != values.end();
}
command_entry command_bulk::value(const std::string &key) {
auto& values = this->handle->values;
auto index = values.find(key);
if(index == values.end()) {
if(!this->handle->handle->editable)
throw command_value_missing_exception(this->bulk_index, key);
auto result = make_shared<impl::command_value>();
values[key] = result;
return command_entry(result);
}
return command_entry(index->second);
}
const command_entry command_bulk::value(const std::string &key) const {
auto& values = this->handle->values;
auto index = values.find(key);
if(index == values.end())
throw command_value_missing_exception(this->bulk_index, key);
return command_entry(index->second);
}
command_entry command_entry::empty{};
*/

View File

@ -1,641 +0,0 @@
#pragma once
#include <any>
#include <memory>
#include <vector>
#include <map>
#include <cassert>
#include <string_view>
#include <deque>
#include <tuple>
#include "Error.h"
#include "command_exception.h"
#include "converters/converter.h"
#ifdef WIN32
#define __attribute__used
#else
#define __attribute__used __attribute__((used))
#endif
namespace ts {
/* data impl stuff */
namespace impl {
struct command_data;
struct command_value {
bool casted = false; /* true if value isn't a std::string */
std::any value;
std::string(*to_string)(const std::any&);
};
struct command_bulk {
command_data* handle;
std::map<std::string, std::shared_ptr<command_value>> values;
};
struct command_data {
std::string command;
bool editable;
std::deque<std::shared_ptr<command_bulk>> bulks;
std::deque<std::string> triggers;
};
}
/* Container stuff */
class command_bulk;
class command_entry;
class command {
public:
struct format {
enum value {
QUERY,
BRACE_ESCAPED_QUERY,
JSON
};
};
static command parse(const std::string_view& /* command data */, bool /* expect type */ = true, bool /* drop non UTF-8 characters */ = false);
explicit command(const std::string& /* command */ = "", bool /* editable */ = true);
[[nodiscard]] const std::string& identifier() const;
void set_identifier(const std::string& /* command */);
command_bulk bulk(size_t /* bulk index */);
[[nodiscard]] const command_bulk bulk(size_t /* bulk index */) const;
[[nodiscard]] size_t bulk_count() const;
inline command_bulk operator[](size_t /* index */);
inline const command_bulk operator[](size_t /* index */) const;
command_entry value(const std::string& /* key */);
[[nodiscard]] const command_entry value(const std::string& /* key */) const;
[[nodiscard]] bool has_value(const std::string& /* key */) const;
command_entry operator[](const std::string& /* key */);
const command_entry operator[](const std::string& /* key */) const;
[[nodiscard]] bool has_trigger(const std::string& /* key */) const;
void set_trigger(const std::string& /* key */, bool /* value */ = true);
std::string build(format::value /* format */ = format::QUERY);
/* TODO add a json object build method */
private:
std::shared_ptr<impl::command_data> handle;
};
class command_bulk {
friend class command;
public:
[[nodiscard]] bool has(const std::string& /* key */) const;
command_entry value(const std::string& /* key */);
[[nodiscard]] command_entry const value(const std::string& /* key */) const;
inline command_entry operator[](const std::string& /* key */);
inline const command_entry operator[](const std::string& /* key */) const;
private:
command_bulk(size_t index, std::shared_ptr<impl::command_bulk> handle) : bulk_index(index), handle(std::move(handle)) {}
size_t bulk_index;
std::shared_ptr<impl::command_bulk> handle;
};
class command_entry {
public:
static command_entry empty;
command_entry() : handle(std::make_shared<impl::command_value>()) {}
command_entry(const command_entry& ref) : handle(ref.handle) {}
command_entry(command_entry&& ref) : handle(std::move(ref.handle)) {}
command_entry&operator=(const command_entry& other) {
this->handle = other.handle;
return *this;
}
inline bool is_empty() const { return !this->handle->value.has_value(); }
command_entry& reset() {
this->handle->value.reset();
return *this;
}
[[nodiscard]] const std::string string() const {
if(this->is_empty()) return "";
if(!this->handle->casted || this->handle->value.type() == typeid(std::string)) //No cast needed
return std::any_cast<std::string>(this->handle->value);
if(!this->handle->to_string) throw command_cannot_uncast_exception();
return this->handle->to_string(this->handle->value);
}
[[nodiscard]] inline const std::string value() const { return (std::string) this->string(); }
[[nodiscard]] inline operator std::string() const {
return this->string();
}
template <typename T, std::enable_if_t<!std::is_same<T, std::string>::value, int> = 0>
T as() {
static_assert(converter<T>::supported, "Target type isn't supported!");
static_assert(!converter<T>::supported || converter<T>::from_string, "Target type dosn't support parsing");
if(this->is_empty()) return T();
if(this->handle->casted) {
if(this->handle->value.type() == typeid(T))
return std::any_cast<T>(this->handle->value);
else
throw command_casted_exception();
} else {
const auto& ref = std::any_cast<const std::string&>(this->handle->value);
this->handle->value = converter<T>::from_string(ref);
this->handle->to_string = converter<T>::to_string;
this->handle->casted = true;
}
return std::any_cast<T>(this->handle->value);
}
template <typename T, std::enable_if_t<std::is_same<T, std::string>::value, int> = 0>
T as() {
return this->string();
}
template <typename T>
inline operator T() {
return this->as<T>();
}
command_entry& melt() {
if(this->handle->casted) {
this->handle->value = this->handle->to_string(this->handle->value);
this->handle->casted = false;
this->handle->to_string = nullptr;
}
return *this;
}
template <typename T, typename std::enable_if<!std::is_same<T, std::string>::value && !std::is_same<T, const char*>::value && !std::is_same<T, const char (&)[]>::value, int>::type = 0>
void set(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 encode");
this->handle->casted = true;
this->handle->value = std::move(value);
this->handle->to_string = converter<T>::to_string;
}
template <typename T, typename std::enable_if<std::is_same<T, std::string>::value, int>::type = 0>
void set(const T& value) {
this->handle->value = value;
this->handle->casted = false;
this->handle->to_string = nullptr;
}
template <int N>
void set(const char (&string)[N]) {
this->set(std::string(string, N - 1));
}
template <typename T>
command_entry&operator=(const T& value) {
this->set(value);
return *this;
}
explicit command_entry(std::shared_ptr<impl::command_value> handle) : handle(std::move(handle)) {}
private:
std::shared_ptr<impl::command_value> handle;
};
namespace descriptor {
namespace tliterals {
template <char... chars>
using tstring = std::integer_sequence<char, chars...>;
#ifndef WIN32
template <typename T, T... chars>
constexpr tstring<chars...> operator""_tstr() { return { }; }
#endif
template <typename>
struct tliteral;
template <char... elements>
struct tliteral<tstring<elements...>> {
static constexpr char string[sizeof...(elements) + 1] = { elements..., '\0' };
};
}
namespace impl {
namespace templates {
template <bool...>
struct _or_ {
constexpr static bool value = false;
};
template <bool T, bool... Args>
struct _or_<T, Args...> {
constexpr static bool value = T || _or_<Args...>::value;
};
template <typename... >
struct index;
template <typename... >
struct tuple_index;
template <typename T, typename... R>
struct index<T, T, R...> : std::integral_constant<size_t, 0>
{ };
template <typename T, typename F, typename... R>
struct index<T, F, R...> : std::integral_constant<size_t, 1 + index<T, R...>::value>
{ };
template <typename T, typename... R>
struct tuple_index<T, std::tuple<R...>> : std::integral_constant<size_t, index<T, R...>::value>
{ };
template <typename T>
struct remove_cr {
typedef T type;
};
template <typename T>
struct remove_cr<const T&> {
typedef T type;
};
}
struct base;
template <class key_t, typename value_type_t, class options, class... extends>
struct field;
struct field_data;
struct field_base;
struct optional_extend;
struct bulk_extend;
template <typename...>
struct command_parser {
constexpr static bool supported = false;
};
inline void parse_field(const std::shared_ptr<field_data>& description, field_base* field, command& cmd);
struct option_data {
bool bulked;
bool optional;
};
template <bool bulked_t, bool optional_t>
struct options {
using object_data_t = option_data;
static constexpr auto is_bulked = bulked_t;
static constexpr auto is_optional = optional_t;
protected:
inline static object_data_t options_object() {
return {
is_bulked,
is_optional
};
}
};
using default_options = options<false, false>;
struct base {
virtual ~base() = default;
};
struct base_data {
int type; /* 1 = field | 2 = switch | 3 = command handle */
option_data options;
};
struct field_base : public base {
virtual std::vector<command_entry>& ref_values() = 0;
virtual const std::vector<command_entry>& ref_values() const = 0;
};
struct field_data : public base_data {
const char* key;
const std::type_info& field_type;
void* from_string;
void* to_string;
};
template <class key_t, typename value_type_t, class options, class... extends>
struct field : public field_base, public options, public extends... {
friend struct command_parser<field<key_t, value_type_t, options, extends...>>;
static_assert(converter<value_type_t>::supported, "Target type isn't supported!");
static_assert(!converter<value_type_t>::supported || converter<value_type_t>::from_string, "Target type dosn't support parsing");
static_assert(impl::templates::_or_<!std::is_empty<extends>::value...>::value == false, "Extensions could not have data members");
protected:
using object_t = field_data;
using value_type = value_type_t;
static constexpr auto key = key_t::string;
static constexpr auto from_string = converter<value_type_t>::from_string;
public:
template <bool flag = true /*, std::enable_if_t<!templates::_or_<std::is_same<extends, optional_extend>::value...>::value, int> = 0 */>
using as_optional = field<key_t, value_type_t, impl::options<options::is_bulked, flag>, optional_extend, extends...>;
template <bool flag = true /*, std::enable_if_t<!templates::_or_<std::is_same<extends, bulk_extend>::value...>::value, int> = 0 */>
using as_bulked = field<key_t, value_type_t, impl::options<flag, options::is_optional>, bulk_extend, extends...>;
using optional = as_optional<true>;
using bulked = as_bulked<true>;
inline static std::shared_ptr<object_t> describe() {
return std::make_shared<object_t>(
object_t {
1,
options::options_object(),
key,
typeid(value_type_t),
(void*) converter<value_type_t>::from_string,
(void*) converter<value_type_t>::to_string
}
);
}
inline value_type_t value() const {
command_entry& value = this->get_command_entry();
return value.as<value_type_t>();
}
inline command_entry& get_command_entry() const {
if(this->values.empty())
throw command_value_missing_exception{0, key};
const auto& front = this->values.front();
return *(command_entry*) &front;
}
template <typename T>
inline T as() const {
command_entry& value = this->get_command_entry();
return value.as<T>();
}
template <typename T>
inline operator T() const {
return this->as<T>();
}
std::vector<command_entry>& ref_values() final { return this->values; }
const std::vector<command_entry>& ref_values() const final { return this->values; }
protected:
std::vector<command_entry> values;
};
struct optional_extend {
public:
inline bool has_value() const {
auto base = dynamic_cast<field_base*>((struct base*) this);
assert(base);
const auto& values = base->ref_values();
return !values.empty() && !values[0].is_empty();
}
template <typename T>
inline T get_or(T&& value = T{}) const {
auto base = dynamic_cast<field_base*>((struct base*) this);
assert(base);
auto& values = base->ref_values();
if(values.empty() || values[0].is_empty())
return value;
return values.front().as<T>();
}
};
struct bulk_extend {
public:
inline bool has_index(size_t index) const {
return !this->at(index).is_empty();
}
inline size_t length() const {
auto base = dynamic_cast<field_base*>((struct base*) this);
assert(base);
return base->ref_values().size();
}
inline command_entry at(size_t index) const {
auto base = dynamic_cast<field_base*>((struct base*) this);
assert(base);
auto& values = base->ref_values();
if(index > values.size())
throw command_bulk_exceed_index_exception();
return values[index];
}
inline command_entry operator[](size_t index) const {
return this->at(index);
}
};
struct trigger_base : public base {
virtual bool& ref_flag() = 0;
};
struct trigger_data : public base_data {
const char* key;
};
template <class key_t, class options>
struct trigger : public trigger_base, public options {
protected:
static constexpr auto key = key_t::string;
public:
using object_t = trigger_data;
inline static std::shared_ptr<object_t> describe() {
return std::make_shared<object_t>(
object_t {
2,
options::options_object(),
key
}
);
}
inline bool is_set() const { return this->flag_set; }
operator bool() const { return this->flag_set; }
bool& ref_flag() override {
return this->flag_set;
}
private:
bool flag_set = false;
};
template <class key_t, class options, class... extends>
struct command_parser<field<key_t, options, extends...>> {
constexpr static bool supported = true;
typedef field<key_t, options, extends...> field_t;
using descriptor_t = std::shared_ptr<typename field_t::object_t>;
inline static descriptor_t describe() {
return field_t::describe();
}
inline static field_t apply(descriptor_t& descriptor, command& cmd) {
assert(descriptor->type == 1);
field_t result{};
//if(!description->options.optional && !cmd.has_value(description->key))
// throw command_value_missing_exception();
auto& values = result.ref_values();
values.clear();
if(descriptor->options.bulked) {
values.resize(cmd.bulk_count());
for(size_t bulk_index = 0; bulk_index < cmd.bulk_count(); bulk_index++) {
if(!cmd[bulk_index].has(descriptor->key)) {
if(!descriptor->options.optional)
throw command_value_missing_exception(bulk_index, descriptor->key);
else
values[bulk_index] = command_entry::empty;
} else {
values[bulk_index] = cmd[bulk_index][descriptor->key];
}
}
} else {
if(!cmd.has_value(descriptor->key)) {
if(!descriptor->options.optional)
throw command_value_missing_exception(0, descriptor->key);
else
values.push_back(command_entry::empty);
} else
values.push_back(cmd[descriptor->key]);
}
return result;
}
};
template <typename key_t, class options>
struct command_parser<trigger<key_t, options>> {
constexpr static bool supported = true;
typedef trigger<key_t, options> trigger_t;
using descriptor_t = std::shared_ptr<typename trigger_t::object_t>;
inline static descriptor_t describe() {
return trigger_t::describe();
}
inline static trigger_t apply(descriptor_t& descriptor, command& cmd) {
assert(descriptor->type == 2);
trigger_t result{};
result.ref_flag() = cmd.has_trigger(descriptor->key);
return result;
}
};
struct command_data : public base_data { };
template <>
struct command_parser<command&> {
constexpr static bool supported = true;
using descriptor_t = std::shared_ptr<command_data>;
inline static descriptor_t describe() { return std::make_shared<command_data>(command_data{{3, {false, false}}}); }
inline static command& apply(descriptor_t& descriptor, command& cmd) {
assert(descriptor->type == 3);
return cmd;
}
};
template <typename C>
struct command_parser<C> {
constexpr static bool supported = false;
using descriptor_t = std::shared_ptr<nullptr_t>;
inline static descriptor_t describe() {
return nullptr;
}
inline static command& apply(descriptor_t& descriptor, command& cmd) {
return cmd;
}
};
}
template <class key_t, typename value_type_t>
using field = impl::field<key_t, value_type_t, impl::default_options>;
template <class key_t>
using trigger = impl::trigger<key_t, impl::default_options>;
template <typename... args_t>
inline std::array<std::shared_ptr<struct impl::base_data>, sizeof...(args_t)> describe_function(void(*)(args_t...)) {
static_assert(!impl::templates::_or_<!impl::command_parser<typename impl::templates::remove_cr<args_t>::type>::supported...>::value, "Not any function argument type is supported");
return {impl::command_parser<typename impl::templates::remove_cr<args_t>::type>::describe()...};
}
struct invocable_function {
void operator()(command& command) { this->invoke(command); }
virtual void invoke(command& command) = 0;
};
template <typename... args_t>
struct typed_invocable_function : public invocable_function {
using args_tuple_t = std::tuple<args_t...>;
template <typename arg_t>
using command_parser_t = impl::command_parser<typename impl::templates::remove_cr<arg_t>::type>;
using descriptors_t = std::tuple<typename command_parser_t<args_t>::descriptor_t...>;
descriptors_t descriptors;
void(*function)(args_t...);
void invoke(command& command) override {
this->function(command_parser_t<args_t>::apply(std::get<impl::templates::tuple_index<args_t, args_tuple_t>::value>(descriptors), command)...);
}
};
template <typename... args_t, typename typed_function = typed_invocable_function<args_t...>>
std::shared_ptr<invocable_function> parse_function(void(*function)(args_t...)) {
auto result = std::make_shared<typed_function>();
result->function = function;
result->descriptors = {impl::command_parser<typename impl::templates::remove_cr<args_t>::type>::describe()...};
return result;
}
template <typename... args_t>
void invoke_function(void(*function)(args_t...), command& command) {
auto descriptor = parse_function(function);
(*descriptor)(command);
}
/* converts a literal into a template literal */
#define _tlit(literal) ::ts::descriptor::tliterals::tliteral<decltype(literal ##_tstr)>
#define tl(lit) _tlit(lit)
}
//using desc = descriptor::base<descriptor::impl::default_options>;
}
#include "command_internal.h"

38
src/query/command3.cpp Normal file
View File

@ -0,0 +1,38 @@
//
// Created by wolverindev on 25.01.20.
//
#include "command3.h"
using namespace ts;
command_bulk command_parser::empty_bulk{std::string::npos, ""};
bool command_parser::parse(bool command) {
this->data = this->_command;
this->index = std::string::npos;
size_t index{0}, findex;
if(command) {
index = this->_command.find(' ', index);
if(index == std::string::npos) {
this->command_type = this->_command;
return true;
} else {
this->command_type = this->data.substr(0, index);
}
index++;
}
this->_bulks.reserve(4);
while(index < this->_command.size()) {
findex = this->_command.find('|', index);
if(findex == std::string::npos)
findex = this->_command.size();
auto& bulk = this->_bulks.emplace_back(this->_bulks.size() - 1, this->data.substr(index, findex - index));
index = findex + 1;
}
return true;
}

124
src/query/command3.h Normal file
View File

@ -0,0 +1,124 @@
#pragma once
#include <string>
#include <cstddef>
#include <vector>
#include "escape.h"
#include "converters/converter.h"
#include "command_exception.h"
namespace ts {
namespace impl {
class command_string_parser {
public:
[[nodiscard]] inline bool is_empty() const noexcept { return this->data.empty(); }
[[nodiscard]] inline std::string_view value_raw(const std::string_view& key) const {
bool tmp;
auto result = this->value_raw(key, tmp);
if(!tmp) throw command_value_missing_exception{index, std::string{key}};
return result;
}
[[nodiscard]] inline std::string_view value_raw(const std::string_view& key, bool& has_been_found) const noexcept {
has_been_found = false;
size_t index{0}, findex, max{this->data.size()}, key_size{key.size()};
do {
findex = this->data.find(key, index);
if(findex > max) return std::string_view{};
/* not starting with a space so not a match */
if(findex != 0 && this->data[findex - 1] != ' ') {
index = findex + key_size;
continue;
}
findex += key_size;
if(findex < max) {
if(findex < max && this->data[findex] != '=') {
index = findex + key_size;
continue;
}
has_been_found = true;
return this->data.substr(findex + 1, this->data.find(' ', findex + 1) - findex - 1);
} else {
has_been_found = true;
return std::string_view{};
}
} while(true);
}
[[nodiscard]] inline std::string value(const std::string_view& key) const {
const auto value = this->value_raw(key);
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!");
static_assert(!converter<T>::supported || converter<T>::from_string, "Target type dosn't support parsing");
return converter<T>::from_string(this->value(key));
}
protected:
command_string_parser(size_t index, std::string_view data) : index{index}, data{std::move(data)} {}
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)} {}
};
class command_parser : public impl::command_string_parser {
public:
enum struct parse_status {
succeeded,
failed
};
explicit command_parser(std::string command) : _command{std::move(command)}, impl::command_string_parser{std::string::npos, this->_command} { }
bool parse(bool /* contains identifier */);
[[nodiscard]] inline const std::string_view& identifier() const noexcept { return this->command_type; }
[[nodiscard]] inline size_t bulk_count() const noexcept { return this->_bulks.size(); }
[[nodiscard]] inline const command_bulk& bulk(size_t index) const noexcept {
if(this->_bulks.size() <= index) return empty_bulk;
return this->_bulks[index];
}
const command_bulk& operator[](size_t index) const { return this->bulk(index); }
[[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 -= 1;
if(index > key.size()) return false;
if(this->_command_view[index] == '-') return index == 0 || this->_command_view[index - 1] == ' ';
index += 2;
} while(true);
}
[[nodiscard]] const std::vector<command_bulk>& bulks() const { return this->_bulks; }
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{};
};
}

View File

@ -1,23 +1,23 @@
#pragma once
#include "Definitions.h"
#include "command2.h"
#include "command_handler.h"
namespace ts {
namespace cconstants {
typedef descriptor::field<tl("return_code"), std::string> return_code;
typedef command_handler::field<tl("return_code"), std::string> return_code;
typedef descriptor::field<tl("sid"), ServerId> server_id;
typedef command_handler::field<tl("sid"), ServerId> server_id;
typedef descriptor::field<tl("clid"), ClientId> client_id;
typedef descriptor::field<tl("cldbid"), ClientDbId> client_database_id;
typedef command_handler::field<tl("clid"), ClientId> client_id;
typedef command_handler::field<tl("cldbid"), ClientDbId> client_database_id;
typedef descriptor::field<tl("cid"), ChannelId> channel_id;
typedef descriptor::field<tl("cpid"), ChannelId> channel_parent_id;
typedef command_handler::field<tl("cid"), ChannelId> channel_id;
typedef command_handler::field<tl("cpid"), ChannelId> channel_parent_id;
typedef descriptor::field<tl("cgid"), GroupId> channel_group_id;
typedef descriptor::field<tl("cgid"), GroupId> server_group_id;
typedef command_handler::field<tl("cgid"), GroupId> channel_group_id;
typedef command_handler::field<tl("cgid"), GroupId> server_group_id;
//FIXME
/* typedef descriptor::field<tl("permid"), permission::PermissionType> permission_id;

391
src/query/command_handler.h Normal file
View File

@ -0,0 +1,391 @@
#pragma once
#include <any>
#include <memory>
#include <vector>
#include <map>
#include <cassert>
#include <string_view>
#include <deque>
#include <tuple>
#include "Error.h"
#include "command_exception.h"
#include "converters/converter.h"
#include "command3.h"
#ifdef WIN32
#define __attribute__used
#else
#define __attribute__used __attribute__((used))
#endif
namespace ts {
namespace command_handler {
namespace tliterals {
template <char... chars>
using tstring = std::integer_sequence<char, chars...>;
#ifndef WIN32
template <typename T, T... chars>
constexpr tstring<chars...> operator""_tstr() { return { }; }
#endif
template <typename>
struct tliteral;
template <char... elements>
struct tliteral<tstring<elements...>> {
static constexpr char string[sizeof...(elements) + 1] = { elements..., '\0' };
};
}
/* general description of a function */
struct parameter_description {
int type; /* 1 = field | 2 = switch | 3 = command handle */
};
struct parameter_description_field : public parameter_description {
const char* key;
bool optional;
const std::type_info& field_type;
};
struct parameter_description_switch : public parameter_description {
const char* key;
};
struct parameter_description_command : public parameter_description { };
struct invocable_function {
void operator()(command_parser& command) { this->invoke(command); }
virtual void invoke(command_parser& command) = 0;
};
namespace impl {
namespace templates {
template <bool...>
struct _or_ {
constexpr static bool value = false;
};
template <bool T, bool... Args>
struct _or_<T, Args...> {
constexpr static bool value = T || _or_<Args...>::value;
};
template <typename... >
struct index;
template <typename... >
struct tuple_index;
template <typename T, typename... R>
struct index<T, T, R...> : std::integral_constant<size_t, 0>
{ };
template <typename T, typename F, typename... R>
struct index<T, F, R...> : std::integral_constant<size_t, 1 + index<T, R...>::value>
{ };
template <typename T, typename... R>
struct tuple_index<T, std::tuple<R...>> : std::integral_constant<size_t, index<T, R...>::value>
{ };
template <typename T>
struct remove_cr {
typedef T type;
};
template <typename T>
struct remove_cr<const T&> {
typedef T type;
};
}
template <typename...>
struct command_invoker {
constexpr static bool supported = false;
};
struct function_parameter {
virtual ~function_parameter() = default;
virtual void parse(const command_parser& /* parser */) = 0;
};
template <typename key_t, typename value_t, bool optional, bool bulked>
class value_container;
/* single value implementation */
template <typename value_t>
class single_value_base {
public:
[[nodiscard]] inline const value_t& value() const {
if(!this->_value.has_value()) throw command_value_missing_exception{0, "unknown"}; /* this should never happen! */
assert(this->_value.has_value());
return this->_value.value();
}
inline operator value_t() const {
return this->value();
}
protected:
static constexpr bool bulked_value = false;
std::optional<value_t> _value{};
};
template <typename key_t, typename value_t>
class value_container<key_t, value_t, false, false> : public single_value_base<value_t> {
protected:
void _parse(const command_parser& parser) {
this->_value = std::make_optional(parser.value_as<value_t>(key_t::string)); /* will cause a not found exception if missing */
}
};
template <typename key_t, typename value_t>
class value_container<key_t, value_t, true, false> : public single_value_base<value_t> {
public:
[[nodiscard]] inline bool has_value() const { return this->_value.has_value(); }
[[nodiscard]] inline const value_t& value_or(value_t&& fallback) const {
if(this->_value.has_value())
return this->value();
return fallback;
}
protected:
void _parse(const command_parser& parser) {
bool found{};
(void) parser.value_raw(key_t::string, found);
if(found)
this->_value = parser.value_as<value_t>(key_t::string);
}
};
/* optional bulk implementation */
template <typename key_t, typename value_t>
class value_container<key_t, value_t, true, true> {
public:
[[nodiscard]] inline bool has_value(size_t index) const { return this->_values[index].has_value(); }
[[nodiscard]] inline const value_t& value(size_t index) const {
if(!this->_values[index].has_value()) throw command_value_missing_exception{0, "unknown"}; /* this should never happen! */
assert(this->_values[index].has_value());
return this->_values[index].value();
}
[[nodiscard]] inline const value_t& value_or(size_t index, value_t&& fallback) const {
if(this->has_value(index))
return this->value(index);
return fallback;
}
protected:
static constexpr bool bulked_value = true;
void _parse(const command_parser& parser) {
this->_values.reserve(parser.bulk_count());
for(const auto& bulk : parser.bulks()) {
auto& value = this->_values.emplace_back();
bool found{};
(void) bulk.value_raw(key_t::string, found);
if(found)
value = bulk.value_as<value_t>(key_t::string);
}
}
private:
std::vector<std::optional<value_t>> _values{};
};
/* non optional bulk implementation */
template <typename key_t, typename value_t>
class value_container<key_t, value_t, false, true> {
public:
[[nodiscard]] inline const value_t& value(size_t index) const {
return this->_values[index];
}
protected:
static constexpr bool bulked_value = true;
void _parse(const command_parser& parser) {
this->_values.reserve(parser.bulk_count());
for(const auto& bulk : parser.bulks())
this->_values.push_back(bulk.value_as<value_t>(key_t::string)); /* will cause a not found exception if missing */
}
private:
std::vector<value_t> _values{};
};
template <class key_t, typename value_type_t, class is_optional_t = std::false_type, class bulk_extend = value_container<key_t, value_type_t, is_optional_t::value, false>>
struct field : public function_parameter, public bulk_extend {
friend struct command_invoker<field<key_t, value_type_t, is_optional_t, bulk_extend>>;
static_assert(converter<value_type_t>::supported, "Target type isn't supported!");
static_assert(!converter<value_type_t>::supported || converter<value_type_t>::from_string, "Target type dosn't support parsing");
public:
template <bool flag = true>
using as_optional = field<key_t, value_type_t, std::integral_constant<bool, flag>, value_container<key_t, value_type_t, flag, bulk_extend::bulked_value>>;
template <bool flag>
using as_bulked = field<key_t, value_type_t, is_optional_t, value_container<key_t, value_type_t, is_optional_t::value, flag>>;
using optional = as_optional<true>;
using bulked = as_bulked<true>;
inline static const parameter_description* describe() {
static std::unique_ptr<parameter_description> description;
if(!description) {
description = std::make_unique<parameter_description>(parameter_description_field{
1,
key_t::string,
is_optional_t::value,
typeid(value_type_t)
});
}
return &*description;
}
[[nodiscard]] inline constexpr bool is_optional() { return is_optional_t::value; }
[[nodiscard]] inline constexpr bool is_bulked() { return bulk_extend::bulked_value; }
~field() override = default;
void parse(const command_parser& parser) override { this->_parse(parser); }
};
template <class key_t>
struct trigger : public function_parameter {
public:
inline static const parameter_description* describe() {
static std::unique_ptr<parameter_description_switch> description;
if(!description) {
description = std::make_unique<parameter_description_switch>(parameter_description_switch{
2,
key_t::string
});
}
return &*description;
}
inline bool is_set() const { return this->flag_set; }
operator bool() const { return this->flag_set; }
void parse(const command_parser& parser) override { this->flag_set = parser.has_switch(key_t::string); }
private:
bool flag_set = false;
};
template <typename key_t, typename value_t, class optional_extend, class bulk_extend>
struct command_invoker<field<key_t, value_t, optional_extend, bulk_extend>> {
constexpr static bool supported = true;
typedef field<key_t, value_t, optional_extend, bulk_extend> field_t;
inline static const parameter_description* describe() {
return field_t::describe();
}
inline static field_t apply(command_parser& cmd) {
field_t result{};
result.parse(cmd);
return result;
}
};
template <typename key_t>
struct command_invoker<trigger<key_t>> {
constexpr static bool supported = true;
inline static const parameter_description* describe() {
return trigger<key_t>::describe();
}
inline static trigger<key_t> apply(command_parser& cmd) {
trigger<key_t> result{};
result.parse(cmd);
return result;
}
};
template <>
struct command_invoker<command_parser&> {
constexpr static bool supported = true;
inline static const parameter_description* describe() {
static std::unique_ptr<parameter_description> description;
if(!description)
description = std::make_unique<parameter_description>(parameter_description_command{3});
return &*description;
}
inline static command_parser& apply(command_parser& cmd) {
return cmd;
}
};
template <typename C>
struct command_invoker<C> {
constexpr static bool supported = false;
using descriptor_t = std::shared_ptr<nullptr_t>;
inline static descriptor_t describe() {
return nullptr;
}
inline static command_parser& apply(descriptor_t& descriptor, command_parser& cmd) {
return cmd;
}
};
template <typename... args_t>
struct typed_invocable_function : public invocable_function {
template <typename arg_t>
using command_invoker_t = command_invoker<typename impl::templates::remove_cr<arg_t>::type>;
void(*function)(args_t...);
void invoke(command_parser& command) override {
this->function(command_invoker_t<args_t>::apply(command)...);
}
};
}
template <class key_t, typename value_type_t>
using field = impl::field<key_t, value_type_t>;
template <class key_t>
using trigger = impl::trigger<key_t>;
template <typename... args_t>
inline std::array<const parameter_description*, sizeof...(args_t)> describe_function(void(*)(args_t...)) {
static_assert(!impl::templates::_or_<(!impl::command_invoker<typename impl::templates::remove_cr<args_t>::type>::supported)...>::value, "Not any function argument type is supported");
return {impl::command_invoker<typename impl::templates::remove_cr<args_t>::type>::describe()...};
}
template <typename... args_t, typename typed_function = impl::typed_invocable_function<args_t...>>
std::shared_ptr<invocable_function> parse_function(void(*function)(args_t...)) {
auto result = std::make_shared<typed_function>();
result->function = function;
return result;
}
/* converts a literal into a template literal */
#define _tlit(literal) ::ts::command_handler::tliterals::tliteral<decltype(literal ##_tstr)>
#define tl(lit) _tlit(lit)
}
//using desc = descriptor::base<descriptor::impl::default_options>;
}
#include "command_internal.h"

View File

@ -2,31 +2,9 @@
namespace ts {
/* some inlineable implementations */
inline command_bulk command::operator[](size_t index) {
return this->bulk(index);
}
inline command_entry command::operator[](const std::string &key) {
return this->value(key);
}
inline command_entry command_bulk::operator[](const std::string &key) {
return this->value(key);
}
inline const command_bulk command::operator[](size_t index) const {
return this->bulk(index);
}
inline const command_entry command::operator[](const std::string &key) const {
return this->value(key);
}
inline const command_entry command_bulk::operator[](const std::string &key) const {
return this->value(key);
}
}
#ifndef WIN32
using ts::descriptor::tliterals::operator""_tstr;
using ts::command_handler::tliterals::operator""_tstr;
#endif

View File

@ -0,0 +1,8 @@
//
// Created by wolverindev on 25.01.20.
//
#ifndef TEASPEAK_PARENT_COMMAND_UNUSED_H
#define TEASPEAK_PARENT_COMMAND_UNUSED_H
#endif //TEASPEAK_PARENT_COMMAND_UNUSED_H

View File

@ -2,9 +2,7 @@
#include <string>
namespace ts {
namespace query {
extern std::string escape(std::string);
extern std::string unescape(std::string, bool /* throw error */);
}
namespace ts::query {
extern std::string escape(std::string);
extern std::string unescape(std::string, bool /* throw error */);
}

View File

@ -1,4 +1,4 @@
#include <src/query/command2.h>
#include <src/query/command3.h>
#include <codecvt>
#include <locale>
#include <string>
@ -9,6 +9,7 @@
#include <functional>
#include "PermissionManager.h"
#include "src/query/command_handler.h"
#include "src/query/command_constants.h"
using namespace std;
@ -16,34 +17,13 @@ using namespace ts;
using namespace license::teamspeak;
template <class key_t, typename value_type_t>
using field = ts::descriptor::field<key_t, value_type_t>;
using field = ts::command_handler::field<key_t, value_type_t>;
template <class key_t>
using trigger = ts::descriptor::trigger<key_t>;
template<unsigned N>
class FixedString {
public:
constexpr FixedString(char const* s) {
for (unsigned i = 0; i < N; ++i)
buf[i] = s[i];
}
constexpr operator const char*() const { return buf; }
[[nodiscard]] constexpr const char* c_str() const { return buf; }
private:
char buf[N + 1]{};
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;
template<FixedString T>
void test() {
std::cout << "Parameter: " << T.c_str() << "\n";
}
using trigger = ts::command_handler::trigger<key_t>;
void handleCommand(
ts::command& _cmd,
ts::command_parser& parser,
const cconstants::return_code::optional& return_code,
const field<tl("key_a"), int>& key_a,
const field<tl("key_b"), string>::optional& key_b,
@ -53,20 +33,15 @@ void handleCommand(
if(key_a.value() < 10) {
__asm__("nop");
}
__asm__("nop");
auto b = key_c.as<string>();
__asm__("nop");
string key_c_str = key_c;
__asm__("nop");
auto c = key_b.has_value();
__asm__("nop");
(void) key_c[1].value();
(void) key_c.value(1);
__asm__("nop");
(void) return_code.get_or<string>("XXX");
//cout << << endl;
//cout << "Return code: " << return_code.get_or<string>("XXX") << endl;
(void) return_code.value_or("XXX");
cout << key_b.has_value() << endl;
cout << "Return code: " << return_code.value_or("XXX") << endl;
__asm__("nop");
}
@ -93,38 +68,16 @@ void eval_test(command_result x) {
}
}
struct A {
virtual ~A() { puts("~A\n"); }
};
struct B : public A {
virtual ~B() { puts("~B\n"); }
};
int main() {
make_command_result(error::accounting_slot_limit_reached, "");
/*
0x559e5259a479 <main()+41>: lea 0xa0(%rsp),%rbx
0x559e5259a481 <main()+49>: lea 0x30(%rsp),%r14
0x559e5259a486 <main()+54>: callq 0x559e525579d0 <operator new(unsigned long)@plt>
0x559e5259a48b <main()+59>: lea 0x17e6a6(%rip),%rdi # 0x559e52718b38
0x559e5259a492 <main()+66>: mov %rax,%rbp
0x559e5259a495 <main()+69>: callq 0x559e52558b10 <puts@plt>
0x559e5259a49a <main()+74>: mov $0x1,%esi
0x559e5259a49f <main()+79>: mov %rbp,%rdi
0x559e5259a4a2 <main()+82>: callq 0x559e525573d0 <operator delete(void*, unsigned long)@plt>
*/
{
A* var = new B{};
delete var;
}
test<"abs">();
ts::command_handler::impl::field<tl("A"), int>::as_bulked<false> a;
std::cout << "Optional: " << a.is_optional() << "\n";
//test<"abs">();
//for(const auto& error : avariableErrors)
// cout << error.name << " = " << hex << "0x" << error.errorId << "," << endl;
eval_test(test());
eval_test(test2());
eval_test(test3());
//eval_test(test());
//eval_test(test2());
//eval_test(test3());
/*
ios_base::sync_with_stdio(false); // Avoids synchronization with C stdio on gcc
// (either localize both or disable sync)
@ -160,9 +113,12 @@ int main() {
//register_function(handleCommand);
/*
cout << sizeof(command_result) << endl;
ts::command cmd("notify");
*/
/*
cout << ts::command::parse("test a=b ").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
cout << ts::command::parse("test a=").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
cout << ts::command::parse("test a").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
@ -170,7 +126,17 @@ int main() {
cout << ts::command::parse("a=c | a=c -x", false).build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
cout << ts::command::parse("a a=c|a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
cout << ts::command::parse("a a=c a=c2 -z | -? a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
*/
std::cout << "Command v3:\n";
{
auto command = ts::command_parser{"a a=c a=c2 -z | -? a=2 key_c=c"};
if(!command.parse(true)) return 1;
std::cout << command.bulk_count() << "\n";
std::cout << command.bulk(1).value("a") << "\n";
std::cout << command.has_switch("?") << "\n";
};
/*
*
cmd[0]["key_a"] = 2;
@ -182,18 +148,14 @@ int main() {
cmd.set_trigger("test2");
cout << "Key_A => " << cmd[0]["key_a"].string() << endl;
*/
cmd["key_a"] = "0";
cmd["key_b"] = "key_b_value";
cmd["return_code"] = "ASD";
cmd[0]["key_c"] = "key_c_value_0";
cmd[1]["key_c"] = "key_c_value_1";
cmd.set_trigger("test");
auto result = ts::descriptor::describe_function(handleCommand);
auto result = ts::command_handler::describe_function(handleCommand);
auto cmd_handler = ts::command_handler::parse_function(handleCommand);
auto cmd = ts::command_parser{"a key_a=77 a=c a=c2 -z | -? key_c=3333 c=22 a=c return_code=234"};
if(!cmd.parse(true)) return 1;
auto cmd_handler = ts::descriptor::parse_function(handleCommand);
cmd_handler->invoke(cmd);
cout << cmd.build() << endl;
//auto v = ts::descriptor::entry::bulked::val;
return 0;