diff --git a/src/BasicChannel.h b/src/BasicChannel.h index 8e7f4be..46d19d1 100644 --- a/src/BasicChannel.h +++ b/src/BasicChannel.h @@ -70,6 +70,14 @@ namespace ts { return BasicChannel::permission_granted(data,granted_value, require_granted_value); } + ts_always_inline bool talk_power_granted(const permission::v2::PermissionFlaggedValue& granted_value) { + return this->permission_granted(permission::i_client_needed_talk_power, granted_value, false); + } + + ts_always_inline std::shared_ptr permissions(){ return this->_permissions; } + virtual void setPermissionManager(const std::shared_ptr&); + virtual void setProperties(const std::shared_ptr&); + private: ts_always_inline static bool permission_granted(const permission::v2::PermissionFlaggedValue& channel_permission_value, const permission::v2::PermissionFlaggedValue& granted_value, bool require_granted_value) { if(!channel_permission_value.has_value || channel_permission_value.value == 0) { @@ -81,14 +89,6 @@ namespace ts { return granted_value.value >= channel_permission_value.value; } - ts_always_inline bool talk_power_granted(const permission::v2::PermissionFlaggedValue& granted_value) { - return this->permission_granted(permission::i_client_needed_talk_power, granted_value, false); - } - - ts_always_inline std::shared_ptr permissions(){ return this->_permissions; } - virtual void setPermissionManager(const std::shared_ptr&); - virtual void setProperties(const std::shared_ptr&); - protected: public: ChannelId channelId() const override; ChannelId previousChannelId() const override; diff --git a/src/PermissionManager.h b/src/PermissionManager.h index 68c59d4..75c975a 100644 --- a/src/PermissionManager.h +++ b/src/PermissionManager.h @@ -15,6 +15,7 @@ #include "./misc/spin_lock.h" #include "Definitions.h" #include "Variable.h" +#include "spdlog/fmt/ostr.h" // must be included #define permNotGranted (-2) #define PERM_ID_GRANT ((ts::permission::PermissionType) (1 << 15)) @@ -809,9 +810,33 @@ namespace ts { struct PermissionFlaggedValue { 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; } + + 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); } }; static constexpr PermissionFlaggedValue empty_permission_flagged_value{0, false}; + + static constexpr bool permission_granted(const PermissionFlaggedValue& required, const PermissionFlaggedValue& given, bool requires_given = true) { + if(!required.has_value) { + return !requires_given || given.has_power(); + } else if(!given.has_power()) { + return false; + } else if(given.has_infinite_power()) { + return true; + } else if(required.has_infinite_power()) { + return false; + } else { + return given.value >= required.value; + } + } + static constexpr bool permission_granted(const PermissionValue& required, const PermissionFlaggedValue& given, bool requires_given = true) { + return permission_granted({required, true}, given, requires_given); + } + class PermissionManager { public: static constexpr size_t PERMISSIONS_BULK_BITS = 4; /* 16 permissions per block */ @@ -909,6 +934,13 @@ namespace ts { } } +inline std::ostream& operator<<(std::ostream& os, const ts::permission::v2::PermissionFlaggedValue& c) { + if(c.has_value) + return os << c.value; + else + return os << "unset"; +} + DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionType, VARTYPE_INT, std::to_string((int16_t) in), static_cast(in.as())); DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionGroup, VARTYPE_INT, std::to_string((uint16_t) in), static_cast(in.as())); DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionSqlType, VARTYPE_INT, std::to_string((int8_t) in), static_cast(in.as())); \ No newline at end of file diff --git a/src/query/command3.h b/src/query/command3.h index cd77fb5..312ddea 100644 --- a/src/query/command3.h +++ b/src/query/command3.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "escape.h" #include "converters/converter.h" @@ -10,6 +11,36 @@ namespace ts { namespace impl { + inline bool value_raw_impl(const std::string_view& data, const std::string_view& key, size_t& begin, size_t* end) { + size_t index{0}, findex, max{data.size()}, key_size{key.size()}; + do { + findex = data.find(key, index); + if(findex > max) return false; + + /* not starting with a space so not a match */ + if(findex != 0 && data[findex - 1] != ' ') { + index = findex + key_size; + continue; + } + + findex += key_size; + if(findex < max) { + if(findex < max && data[findex] != '=') { + index = findex + key_size; + continue; + } + + begin = findex + 1; + if(end) *end = data.find(' ', findex + 1); + return true; + } else { + begin = max; + if(end) *end = max; + return true; + } + } while(true); + } + class command_string_parser { public: [[nodiscard]] inline bool is_empty() const noexcept { return this->data.empty(); } @@ -22,33 +53,11 @@ namespace ts { } [[nodiscard]] inline std::string_view value_raw(const std::string_view& key, bool& has_been_found) const noexcept { - has_been_found = false; + size_t begin, end; + has_been_found = value_raw_impl(this->data, key, begin, &end); + if(!has_been_found) return {}; - 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); + return this->data.substr(begin, end - begin); } [[nodiscard]] inline std::string value(const std::string_view& key) const { @@ -121,4 +130,101 @@ namespace ts { std::vector _bulks{}; std::vector flags{}; }; + + template > + class command_builder_impl { + public: + explicit command_builder_impl(std::string command, size_t expected_bulk_size = 128, size_t expected_bulks = 1) : _identifier{std::move(command)}, expected_bulk_size{expected_bulk_size} { + for(size_t index = 0; index < expected_bulks; index++) + this->bulks.emplace_back(" ").reserve(expected_bulk_size); + } + + inline command_builder_impl> as_normalized() { + return command_builder_impl>{this->expected_bulk_size, this->_identifier, this->bulks.begin(), this->bulks.end()}; + } + + inline std::string build() const { + if(this->builded.has_value()) + return this->builded.value(); + + std::string result{}; + size_t required_size{this->_identifier.size()}; + for(auto& entry : this->bulks) + required_size += entry.size() + 1; + + result.append(this->_identifier); + for(auto it = this->bulks.begin(); it != this->bulks.end(); it++) { + result.append(*it); + if(it + 1 != this->bulks.end()) + result.append("|"); + } + + this->builded = result; + return result; + } + + 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) { + 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); + } + + template ::value || std::is_same::value), int> = 1> + inline void put(size_t index, const std::string_view& key, const T& value) { + static_assert(converter::supported, "Target type isn't supported!"); + static_assert(!converter::supported || converter::to_string, "Target type dosn't support building"); + auto data = converter::to_string(value); + this->put(index, key, std::string_view{data}); + } + + /* 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 ::value || std::is_same::value), int> = 1> + inline void put_unchecked(size_t index, const std::string_view& key, const T& value) { + static_assert(converter::supported, "Target type isn't supported!"); + static_assert(!converter::supported || converter::to_string, "Target type dosn't support building"); + auto data = converter::to_string(value); + this->put_unchecked(index, key, std::string_view{data}); + } + private: + command_builder_impl(size_t expected, size_t identifier, vector_t::iterator begin, 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); + data.append("="); + data.append(escaped_value); + data.append(" "); + + this->builded.reset(); + } + + const size_t expected_bulk_size; + const std::string _identifier; + mutable std::optional builded{}; + vector_t bulks{}; + }; + + using command_builder = command_builder_impl<>; } \ No newline at end of file diff --git a/src/query/command_constants.h b/src/query/command_constants.h index 1952773..1ebb7cb 100644 --- a/src/query/command_constants.h +++ b/src/query/command_constants.h @@ -7,6 +7,7 @@ namespace ts { namespace cconstants { typedef command_handler::field return_code; + typedef command_handler::field reasonmsg; typedef command_handler::field server_id; @@ -17,7 +18,7 @@ namespace ts { typedef command_handler::field channel_parent_id; typedef command_handler::field channel_group_id; - typedef command_handler::field server_group_id; + typedef command_handler::field server_group_id; //FIXME /* typedef descriptor::field permission_id; diff --git a/test/CommandTest.cpp b/test/CommandTest.cpp index 1e2defc..593608d 100644 --- a/test/CommandTest.cpp +++ b/test/CommandTest.cpp @@ -157,6 +157,14 @@ int main() { cmd_handler->invoke(cmd); + { + ts::command_builder builder{"hello_world"}; + builder.put(0, "hello", "this is hello world"); + builder.put(1, "hello", "this is hello world1"); + builder.put(1, "hello", "this is hello world2"); + builder.put_unchecked(6, "hello", 22); + std::cout << "Result: " << builder.build() << "\n"; + } //auto v = ts::descriptor::entry::bulked::val; return 0; } \ No newline at end of file