From e1ce4159ae9c21d7c8e5bec609c19e101bafff7d Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 30 Aug 2024 14:58:46 +0200 Subject: [PATCH 1/6] Start replacement work --- include/CaptivePortal.h | 7 +- include/CaptivePortalInstance.h | 6 +- include/Common.h | 7 +- include/GatewayClient.h | 5 +- include/GatewayConnectionManager.h | 6 +- include/OtaUpdateManager.h | 1 - include/SemVer.h | 8 +- include/StringView.h | 469 ------------------ include/config/BackendConfig.h | 4 +- include/config/Config.h | 12 +- include/config/WiFiConfig.h | 4 +- include/config/WiFiCredentials.h | 4 +- include/http/HTTPRequestManager.h | 9 +- include/http/JsonAPI.h | 8 +- include/intconv.h | 19 +- include/serialization/WSGateway.h | 5 +- include/util/PartitionUtils.h | 5 +- include/wifi/WiFiManager.h | 4 +- src/CaptivePortal.cpp | 4 +- src/GatewayClient.cpp | 2 +- src/GatewayConnectionManager.cpp | 10 +- src/OtaUpdateManager.cpp | 28 +- src/SemVer.cpp | 76 +-- src/config/BackendConfig.cpp | 2 +- src/config/Config.cpp | 22 +- src/config/WiFiConfig.cpp | 2 +- src/config/WiFiCredentials.cpp | 2 +- .../websocket/gateway/OtaInstall.cpp | 6 +- src/http/HTTPRequestManager.cpp | 26 +- src/http/JsonAPI.cpp | 8 +- src/intconv.cpp | 28 +- src/serial/SerialInputHandler.cpp | 85 ++-- src/serialization/WSGateway.cpp | 2 +- src/util/ParitionUtils.cpp | 2 +- src/wifi/WiFiManager.cpp | 4 +- 35 files changed, 210 insertions(+), 682 deletions(-) delete mode 100644 include/StringView.h diff --git a/include/CaptivePortal.h b/include/CaptivePortal.h index 6272488a..80d412ba 100644 --- a/include/CaptivePortal.h +++ b/include/CaptivePortal.h @@ -1,10 +1,9 @@ #pragma once -#include "StringView.h" - #include #include +#include namespace OpenShock::CaptivePortal { void SetAlwaysEnabled(bool alwaysEnabled); @@ -15,9 +14,9 @@ namespace OpenShock::CaptivePortal { bool IsRunning(); void Update(); - bool SendMessageTXT(uint8_t socketId, StringView data); + bool SendMessageTXT(uint8_t socketId, std::string_view data); bool SendMessageBIN(uint8_t socketId, const uint8_t* data, std::size_t len); - bool BroadcastMessageTXT(StringView data); + bool BroadcastMessageTXT(std::string_view data); bool BroadcastMessageBIN(const uint8_t* data, std::size_t len); } // namespace OpenShock::CaptivePortal diff --git a/include/CaptivePortalInstance.h b/include/CaptivePortalInstance.h index 75388705..0b245c63 100644 --- a/include/CaptivePortalInstance.h +++ b/include/CaptivePortalInstance.h @@ -1,6 +1,5 @@ #pragma once -#include "StringView.h" #include "WebSocketDeFragger.h" #include @@ -11,6 +10,7 @@ #include #include +#include namespace OpenShock { class CaptivePortalInstance { @@ -18,9 +18,9 @@ namespace OpenShock { CaptivePortalInstance(); ~CaptivePortalInstance(); - bool sendMessageTXT(uint8_t socketId, StringView data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); } + bool sendMessageTXT(uint8_t socketId, std::string_view data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); } bool sendMessageBIN(uint8_t socketId, const uint8_t* data, std::size_t len) { return m_socketServer.sendBIN(socketId, data, len); } - bool broadcastMessageTXT(StringView data) { return m_socketServer.broadcastTXT(data.data(), data.length()); } + bool broadcastMessageTXT(std::string_view data) { return m_socketServer.broadcastTXT(data.data(), data.length()); } bool broadcastMessageBIN(const uint8_t* data, std::size_t len) { return m_socketServer.broadcastBIN(data, len); } private: diff --git a/include/Common.h b/include/Common.h index bec0778b..0b5e07e5 100644 --- a/include/Common.h +++ b/include/Common.h @@ -1,8 +1,7 @@ #pragma once -#include "StringView.h" - #include +#include #define DISABLE_COPY(TypeName) \ TypeName(const TypeName&) = delete; \ @@ -60,6 +59,6 @@ #endif namespace OpenShock::Constants { - const char* const FW_USERAGENT = OPENSHOCK_FW_USERAGENT; - const StringView FW_USERAGENT_sv = OPENSHOCK_FW_USERAGENT ""_sv; + const char* const FW_USERAGENT = OPENSHOCK_FW_USERAGENT; + const std::string_view FW_USERAGENT_sv = OPENSHOCK_FW_USERAGENT ""_sv; } // namespace OpenShock::Constants diff --git a/include/GatewayClient.h b/include/GatewayClient.h index 87cf3d71..99012e3e 100644 --- a/include/GatewayClient.h +++ b/include/GatewayClient.h @@ -1,11 +1,10 @@ #pragma once -#include "StringView.h" - #include #include #include +#include #include namespace OpenShock { @@ -26,7 +25,7 @@ namespace OpenShock { void connect(const char* lcgFqdn); void disconnect(); - bool sendMessageTXT(StringView data); + bool sendMessageTXT(std::string_view data); bool sendMessageBIN(const uint8_t* data, std::size_t length); bool loop(); diff --git a/include/GatewayConnectionManager.h b/include/GatewayConnectionManager.h index 855c2ae5..750b371f 100644 --- a/include/GatewayConnectionManager.h +++ b/include/GatewayConnectionManager.h @@ -1,10 +1,10 @@ #pragma once #include "AccountLinkResultCode.h" -#include "StringView.h" #include #include +#include namespace OpenShock::GatewayConnectionManager { bool Init(); @@ -12,10 +12,10 @@ namespace OpenShock::GatewayConnectionManager { bool IsConnected(); bool IsLinked(); - AccountLinkResultCode Link(StringView linkCode); + AccountLinkResultCode Link(std::string_view linkCode); void UnLink(); - bool SendMessageTXT(StringView data); + bool SendMessageTXT(std::string_view data); bool SendMessageBIN(const uint8_t* data, std::size_t length); void Update(); diff --git a/include/OtaUpdateManager.h b/include/OtaUpdateManager.h index f4f8bda0..ffb9a45e 100644 --- a/include/OtaUpdateManager.h +++ b/include/OtaUpdateManager.h @@ -3,7 +3,6 @@ #include "FirmwareBootType.h" #include "OtaUpdateChannel.h" #include "SemVer.h" -#include "StringView.h" #include #include diff --git a/include/SemVer.h b/include/SemVer.h index d7a57093..f58bb3e1 100644 --- a/include/SemVer.h +++ b/include/SemVer.h @@ -1,8 +1,8 @@ #pragma once -#include "StringView.h" - #include +#include +#include namespace OpenShock { struct SemVer { @@ -72,5 +72,5 @@ namespace OpenShock { std::string toString() const; }; - bool TryParseSemVer(StringView str, SemVer& out); -} // namespace OpenShock + bool TryParseSemVer(std::string_view str, SemVer& out); +} // namespace OpenShock diff --git a/include/StringView.h b/include/StringView.h deleted file mode 100644 index b1b77c67..00000000 --- a/include/StringView.h +++ /dev/null @@ -1,469 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace OpenShock { - struct StringView { - using value_type = char; - using const_iterator = const value_type*; - using const_reverse_iterator = std::reverse_iterator; - - static const std::size_t npos = std::numeric_limits::max(); - - static constexpr StringView Null() { return StringView(nullptr); } - static constexpr StringView Empty() { return StringView(""); } - - constexpr StringView() : _ptrBeg(nullptr), _ptrEnd(nullptr) { } - constexpr StringView(const char* const ptr) : _ptrBeg(ptr), _ptrEnd(_getStringEnd(ptr)) { } - constexpr StringView(const char* const ptr, std::size_t len) : _ptrBeg(ptr), _ptrEnd(ptr + len) { } - constexpr StringView(const char* const ptrBeg, const char* const ptrEnd) : _ptrBeg(ptrBeg), _ptrEnd(ptrEnd) { } - constexpr StringView(const StringView& str) : _ptrBeg(str._ptrBeg), _ptrEnd(str._ptrEnd) { } - inline StringView(const String& str) : _ptrBeg(str.c_str()), _ptrEnd(str.c_str() + str.length()) { } - inline StringView(const std::string& str) : _ptrBeg(str.c_str()), _ptrEnd(str.c_str() + str.size()) { } - inline StringView(const flatbuffers::String& str) : _ptrBeg(str.c_str()), _ptrEnd(str.c_str() + str.size()) { } - - constexpr bool isNull() const { return _ptrBeg == nullptr || _ptrEnd == nullptr; } - constexpr bool isEmpty() const { return _ptrBeg >= _ptrEnd; } - constexpr bool isNullOrEmpty() const { return isNull() || isEmpty(); } - - constexpr const char* data() const { return _ptrBeg; } - - constexpr const_iterator begin() const { return _ptrBeg; } - const_reverse_iterator rbegin() const { return std::make_reverse_iterator(end()); } - - constexpr const_iterator end() const { return _ptrEnd; } - const_reverse_iterator rend() const { return std::make_reverse_iterator(begin()); } - - constexpr char front() const { return *_ptrBeg; } - constexpr char back() const { return *(_ptrEnd - 1); } - - constexpr std::size_t size() const { - if (isNullOrEmpty()) { - return 0; - } - - return _ptrEnd - _ptrBeg; - } - constexpr std::size_t length() const { return size(); } - - constexpr StringView substr(std::size_t pos, std::size_t count = StringView::npos) const { - if (isNullOrEmpty()) { - return *this; - } - - if (pos > size()) { - return Null(); - } - - if (count == StringView::npos) { - count = size() - pos; - } else if (pos + count > size()) { - return Null(); - } - - return StringView(_ptrBeg + pos, _ptrBeg + pos + count); - } - - constexpr std::size_t find(char needle, std::size_t pos = 0) const { - if (isNullOrEmpty() || pos >= size()) { - return StringView::npos; - } - - std::size_t _size = this->size(); - - for (std::size_t i = pos; i < _size; ++i) { - if (_ptrBeg[i] == needle) { - return i; - } - } - - return StringView::npos; - } - inline std::size_t find(StringView needle, std::size_t pos = 0) const { - if (isNullOrEmpty() || needle.isNullOrEmpty() || pos + needle.size() >= size()) { - return StringView::npos; - } - - const char* ptr = std::search(_ptrBeg + pos, _ptrEnd, needle._ptrBeg, needle._ptrEnd); - if (ptr == _ptrEnd) { - return StringView::npos; - } - - return ptr - _ptrBeg; - } - - inline std::size_t rfind(char needle, std::size_t pos = StringView::npos) const { - if (isNullOrEmpty() || pos >= size()) { - return StringView::npos; - } - - std::size_t _size = this->size(); - - if (pos == StringView::npos) { - pos = _size - 1; - } else if (pos >= _size) { - return StringView::npos; - } - - for (std::size_t i = pos; i > 0; --i) { - if (_ptrBeg[i] == needle) { - return i; - } - } - - return StringView::npos; - } - inline std::size_t rfind(StringView needle, std::size_t pos = StringView::npos) const { - if (isNullOrEmpty() || needle.isNullOrEmpty() || pos + needle.size() >= size()) { - return StringView::npos; - } - - if (pos == StringView::npos) { - pos = size() - 1; - } else if (pos + needle.size() >= size()) { - return StringView::npos; - } - - const char* ptr = std::find_end(_ptrBeg, _ptrBeg + pos, needle._ptrBeg, needle._ptrEnd); - if (ptr == _ptrBeg + pos) { - return StringView::npos; - } - - return ptr - _ptrBeg; - } - - inline StringView beforeDelimiter(char delimiter) const { - std::size_t pos = find(delimiter); - if (pos != StringView::npos) { - return substr(0, pos); - } - - return *this; - } - inline StringView beforeDelimiter(StringView delimiter) const { - std::size_t pos = find(delimiter); - if (pos != StringView::npos) { - return substr(0, pos); - } - - return *this; - } - - inline StringView afterDelimiter(char delimiter) const { - std::size_t pos = find(delimiter); - if (pos != StringView::npos) { - return substr(pos + 1); - } - - return *this; - } - inline StringView afterDelimiter(StringView delimiter) const { - std::size_t pos = find(delimiter); - if (pos != StringView::npos) { - return substr(pos + delimiter.size()); - } - - return *this; - } - - inline std::vector split(char delimiter, std::size_t maxSplits = StringView::npos) const { - if (isNullOrEmpty()) { - return {}; - } - - std::vector result = {}; - - std::size_t pos = 0; - std::size_t splits = 0; - while (pos < size() && splits < maxSplits) { - std::size_t nextPos = find(delimiter, pos); - if (nextPos == StringView::npos) { - nextPos = size(); - } - - result.push_back(substr(pos, nextPos - pos)); - pos = nextPos + 1; - ++splits; - } - - if (pos < size()) { - result.push_back(substr(pos)); - } - - return result; - } - inline std::vector split(StringView delimiter) const { - if (isNullOrEmpty() || delimiter.isNullOrEmpty()) { - return {}; - } - - std::vector result = {}; - - std::size_t pos = 0; - while (pos < size()) { - std::size_t nextPos = find(delimiter, pos); - if (nextPos == StringView::npos) { - nextPos = size(); - } - - result.push_back(substr(pos, nextPos - pos)); - pos = nextPos + delimiter.size(); - } - - return result; - } - inline std::vector split(std::function predicate) const { - if (isNullOrEmpty()) { - return {}; - } - - std::vector result = {}; - - const char* start = nullptr; - for (const char* ptr = _ptrBeg; ptr < _ptrEnd; ++ptr) { - if (predicate(*ptr)) { - if (start != nullptr) { - result.emplace_back(StringView(start, ptr)); - start = nullptr; - } - } else if (start == nullptr) { - start = ptr; - } - } - - if (start != nullptr) { - result.emplace_back(StringView(start, _ptrEnd)); - } - - return result; - } - - inline std::vector splitLines() const { - return split([](char c) { return c == '\r' || c == '\n'; }); - } - inline std::vector splitWhitespace() const { return split(isspace); } - - constexpr bool startsWith(char needle) const { - if (isNull()) { - return false; - } - - return _ptrBeg[0] == needle; - } - constexpr bool startsWith(StringView needle) const { - if (isNull()) { - return needle.isNullOrEmpty(); - } - - return _strEquals(_ptrBeg, _ptrBeg + needle.size(), needle._ptrBeg, needle._ptrEnd); - } - - constexpr bool endsWith(char needle) const { - if (isNullOrEmpty()) { - return false; - } - - return _ptrEnd[-1] == needle; - } - constexpr bool endsWith(StringView needle) const { - if (isNullOrEmpty()) { - return needle.isNullOrEmpty(); - } - - return _strEquals(_ptrEnd - needle.size(), _ptrEnd, needle._ptrBeg, needle._ptrEnd); - } - - constexpr StringView& trimLeft() { - if (isNullOrEmpty()) { - return *this; - } - - while (_ptrBeg < _ptrEnd && isspace(*_ptrBeg)) { - ++_ptrBeg; - } - - return *this; - } - - constexpr StringView& trimRight() { - if (isNullOrEmpty()) { - return *this; - } - - while (_ptrBeg < _ptrEnd && isspace(_ptrEnd[-1])) { - --_ptrEnd; - } - - return *this; - } - - constexpr StringView& trim() { - trimLeft(); - trimRight(); - return *this; - } - - constexpr void clear() { - _ptrBeg = nullptr; - _ptrEnd = nullptr; - } - - inline String toArduinoString() const { - if (isNullOrEmpty()) { - return String(); - } - - return String(_ptrBeg, size()); - } - - inline std::string toString() const { - if (isNullOrEmpty()) { - return std::string(); - } - - return std::string(_ptrBeg, _ptrEnd); - } - - constexpr operator const char*() const { return _ptrBeg; } - - explicit operator String() const { return toArduinoString(); } - - explicit operator std::string() const { return toString(); } - - /// Returns a reference to the character at the specified index, Going out of bounds is undefined behavior - constexpr char const& operator[](int index) const { return _ptrBeg[index]; } - /// Returns a const reference to the character at the specified index, Going out of bounds is undefined behavior - constexpr char const& operator[](std::size_t index) const { return _ptrBeg[index]; } - - constexpr bool operator==(const StringView& other) { - if (this == &other) return true; - - return _strEquals(_ptrBeg, _ptrEnd, other._ptrBeg, other._ptrEnd); - } - constexpr bool operator!=(const StringView& other) { return !(*this == other); } - constexpr bool operator==(const char* const other) { return *this == StringView(other); } - constexpr bool operator!=(const char* const other) { return !(*this == other); } - inline bool operator==(const std::string& other) { return *this == StringView(other); } - inline bool operator!=(const std::string& other) { return !(*this == other); } - - inline bool operator<(const StringView& other) const { - if (this == &other) return false; - - return std::lexicographical_compare(_ptrBeg, _ptrEnd, other._ptrBeg, other._ptrEnd); - } - inline bool operator<=(const StringView& other) const { return *this < other || *this == other; } - inline bool operator>(const StringView& other) const { return !(*this <= other); } - inline bool operator>=(const StringView& other) const { return !(*this < other); } - - constexpr StringView& operator=(const char* const ptr) { - _ptrBeg = ptr; - _ptrEnd = _getStringEnd(ptr); - return *this; - } - constexpr StringView& operator=(const StringView& str) { - _ptrBeg = str._ptrBeg; - _ptrEnd = str._ptrEnd; - return *this; - } - inline StringView& operator=(const std::string& str) { - _ptrBeg = str.c_str(); - _ptrEnd = str.c_str() + str.size(); - return *this; - } - - private: - static constexpr bool _strEquals(const char* aStart, const char* aEnd, const char* bStart, const char* bEnd) { - if (aStart == bStart && aEnd == bEnd) { - return true; - } - if (aStart == nullptr || bStart == nullptr) { - return false; - } - if (aEnd == nullptr) { - aEnd = _getStringEnd(aStart); - } - if (bEnd == nullptr) { - bEnd = _getStringEnd(bStart); - } - - std::size_t aLen = aEnd - aStart; - std::size_t bLen = bEnd - bStart; - if (aLen != bLen) { - return false; - } - - while (aStart < aEnd) { - if (*aStart != *bStart) { - return false; - } - ++aStart; - ++bStart; - } - - return true; - } - static constexpr const char* _getStringEnd(const char* ptr) { - if (ptr == nullptr) { - return nullptr; - } - - while (*ptr != '\0') { - ++ptr; - } - - return ptr; - } - - const char* _ptrBeg; - const char* _ptrEnd; - }; -} // namespace OpenShock - -constexpr OpenShock::StringView operator"" _sv(const char* str, std::size_t len) { - return OpenShock::StringView(str, len); -} - -namespace std { - template<> - struct hash { - std::size_t operator()(OpenShock::StringView str) const { - std::size_t hash = 7; - - for (int i = 0; i < str.size(); ++i) { - hash = hash * 31 + str[i]; - } - - return hash; - } - }; - - struct hash_ci { - std::size_t operator()(OpenShock::StringView str) const { - std::size_t hash = 7; - - for (int i = 0; i < str.size(); ++i) { - hash = hash * 31 + tolower(str[i]); - } - - return hash; - } - }; - - template<> - struct less { - bool operator()(OpenShock::StringView a, OpenShock::StringView b) const { return a < b; } - }; - - struct equals_ci { - bool operator()(OpenShock::StringView a, OpenShock::StringView b) const { return strncasecmp(a.data(), b.data(), std::max(a.size(), b.size())) == 0; } - }; -} // namespace std diff --git a/include/config/BackendConfig.h b/include/config/BackendConfig.h index 4f2b3b48..d99b97c1 100644 --- a/include/config/BackendConfig.h +++ b/include/config/BackendConfig.h @@ -1,14 +1,14 @@ #pragma once #include "config/ConfigBase.h" -#include "StringView.h" #include +#include namespace OpenShock::Config { struct BackendConfig : public ConfigBase { BackendConfig(); - BackendConfig(StringView domain, StringView authToken, StringView lcgOverride); + BackendConfig(std::string_view domain, std::string_view authToken, std::string_view lcgOverride); std::string domain; std::string authToken; diff --git a/include/config/Config.h b/include/config/Config.h index ad901c0e..05f1ee6c 100644 --- a/include/config/Config.h +++ b/include/config/Config.h @@ -7,9 +7,9 @@ #include "config/SerialInputConfig.h" #include "config/WiFiConfig.h" #include "config/WiFiCredentials.h" -#include "StringView.h" #include +#include #include namespace OpenShock::Config { @@ -17,7 +17,7 @@ namespace OpenShock::Config { /* GetAsJSON and SaveFromJSON are used for Reading/Writing the config file in its human-readable form. */ std::string GetAsJSON(bool withSensitiveData); - bool SaveFromJSON(StringView json); + bool SaveFromJSON(std::string_view json); /* GetAsFlatBuffer and SaveFromFlatBuffer are used for Reading/Writing the config file in its binary form. */ flatbuffers::Offset GetAsFlatBuffer(flatbuffers::FlatBufferBuilder& builder, bool withSensitiveData); @@ -57,7 +57,7 @@ namespace OpenShock::Config { bool AnyWiFiCredentials(std::function predicate); - uint8_t AddWiFiCredentials(StringView ssid, StringView password); + uint8_t AddWiFiCredentials(std::string_view ssid, std::string_view password); bool TryGetWiFiCredentialsByID(uint8_t id, WiFiCredentials& out); bool TryGetWiFiCredentialsBySSID(const char* ssid, WiFiCredentials& out); uint8_t GetWiFiCredentialsIDbySSID(const char* ssid); @@ -70,13 +70,13 @@ namespace OpenShock::Config { bool SetOtaUpdateStep(OtaUpdateStep updateStep); bool GetBackendDomain(std::string& out); - bool SetBackendDomain(StringView domain); + bool SetBackendDomain(std::string_view domain); bool HasBackendAuthToken(); bool GetBackendAuthToken(std::string& out); - bool SetBackendAuthToken(StringView token); + bool SetBackendAuthToken(std::string_view token); bool ClearBackendAuthToken(); bool HasBackendLCGOverride(); bool GetBackendLCGOverride(std::string& out); - bool SetBackendLCGOverride(StringView lcgOverride); + bool SetBackendLCGOverride(std::string_view lcgOverride); bool ClearBackendLCGOverride(); } // namespace OpenShock::Config diff --git a/include/config/WiFiConfig.h b/include/config/WiFiConfig.h index e29dfafc..3c780db6 100644 --- a/include/config/WiFiConfig.h +++ b/include/config/WiFiConfig.h @@ -2,15 +2,15 @@ #include "config/ConfigBase.h" #include "config/WiFiCredentials.h" -#include "StringView.h" #include +#include #include namespace OpenShock::Config { struct WiFiConfig : public ConfigBase { WiFiConfig(); - WiFiConfig(StringView accessPointSSID, StringView hostname, const std::vector& credentialsList); + WiFiConfig(std::string_view accessPointSSID, std::string_view hostname, const std::vector& credentialsList); std::string accessPointSSID; std::string hostname; diff --git a/include/config/WiFiCredentials.h b/include/config/WiFiCredentials.h index 50a15ff7..e316070d 100644 --- a/include/config/WiFiCredentials.h +++ b/include/config/WiFiCredentials.h @@ -1,14 +1,14 @@ #pragma once #include "config/ConfigBase.h" -#include "StringView.h" #include +#include namespace OpenShock::Config { struct WiFiCredentials : public ConfigBase { WiFiCredentials(); - WiFiCredentials(uint8_t id, StringView ssid, StringView password); + WiFiCredentials(uint8_t id, std::string_view ssid, std::string_view password); uint8_t id; std::string ssid; diff --git a/include/http/HTTPRequestManager.h b/include/http/HTTPRequestManager.h index 81390ca9..bbaec4e0 100644 --- a/include/http/HTTPRequestManager.h +++ b/include/http/HTTPRequestManager.h @@ -1,11 +1,12 @@ #pragma once -#include "StringView.h" +#include #include #include #include +#include #include namespace OpenShock::HTTP { @@ -33,11 +34,11 @@ namespace OpenShock::HTTP { using GotContentLengthCallback = std::function; using DownloadCallback = std::function; - Response Download(StringView url, const std::map& headers, GotContentLengthCallback contentLengthCallback, DownloadCallback downloadCallback, const std::vector& acceptedCodes = {200}, uint32_t timeoutMs = 10'000); - Response GetString(StringView url, const std::map& headers, const std::vector& acceptedCodes = {200}, uint32_t timeoutMs = 10'000); + Response Download(std::string_view url, const std::map& headers, GotContentLengthCallback contentLengthCallback, DownloadCallback downloadCallback, const std::vector& acceptedCodes = {200}, uint32_t timeoutMs = 10'000); + Response GetString(std::string_view url, const std::map& headers, const std::vector& acceptedCodes = {200}, uint32_t timeoutMs = 10'000); template - Response GetJSON(StringView url, const std::map& headers, JsonParser jsonParser, const std::vector& acceptedCodes = {200}, uint32_t timeoutMs = 10'000) { + Response GetJSON(std::string_view url, const std::map& headers, JsonParser jsonParser, const std::vector& acceptedCodes = {200}, uint32_t timeoutMs = 10'000) { auto response = GetString(url, headers, acceptedCodes, timeoutMs); if (response.result != RequestResult::Success) { return {response.result, response.code, {}}; diff --git a/include/http/JsonAPI.h b/include/http/JsonAPI.h index 934c50a0..43b8070d 100644 --- a/include/http/JsonAPI.h +++ b/include/http/JsonAPI.h @@ -3,19 +3,21 @@ #include "http/HTTPRequestManager.h" #include "serialization/JsonAPI.h" +#include + namespace OpenShock::HTTP::JsonAPI { /// @brief Links the device to the account with the given account link code, returns the device token. Valid response codes: 200, 404 /// @param deviceToken /// @return - HTTP::Response LinkAccount(const char* accountLinkCode); + HTTP::Response LinkAccount(std::string_view accountLinkCode); /// @brief Gets the device info for the given device token. Valid response codes: 200, 401 /// @param deviceToken /// @return - HTTP::Response GetDeviceInfo(StringView deviceToken); + HTTP::Response GetDeviceInfo(std::string_view deviceToken); /// @brief Requests a Live Control Gateway to connect to. Valid response codes: 200, 401 /// @param deviceToken /// @return - HTTP::Response AssignLcg(StringView deviceToken); + HTTP::Response AssignLcg(std::string_view deviceToken); } // namespace OpenShock::HTTP::JsonAPI diff --git a/include/intconv.h b/include/intconv.h index 5f41e877..f0074383 100644 --- a/include/intconv.h +++ b/include/intconv.h @@ -1,16 +1,15 @@ #pragma once -#include "StringView.h" - #include +#include namespace OpenShock::IntConv { - bool stoi8(OpenShock::StringView str, int8_t& val); - bool stou8(OpenShock::StringView str, uint8_t& val); - bool stoi16(OpenShock::StringView str, int16_t& val); - bool stou16(OpenShock::StringView str, uint16_t& val); - bool stoi32(OpenShock::StringView str, int32_t& val); - bool stou32(OpenShock::StringView str, uint32_t& val); - bool stoi64(OpenShock::StringView str, int64_t& val); - bool stou64(OpenShock::StringView str, uint64_t& val); + bool stoi8(std::string_view str, int8_t& val); + bool stou8(std::string_view str, uint8_t& val); + bool stoi16(std::string_view str, int16_t& val); + bool stou16(std::string_view str, uint16_t& val); + bool stoi32(std::string_view str, int32_t& val); + bool stou32(std::string_view str, uint32_t& val); + bool stoi64(std::string_view str, int64_t& val); + bool stou64(std::string_view str, uint64_t& val); } // namespace OpenShock::IntConv diff --git a/include/serialization/WSGateway.h b/include/serialization/WSGateway.h index 770bf9a4..72f52faf 100644 --- a/include/serialization/WSGateway.h +++ b/include/serialization/WSGateway.h @@ -3,14 +3,15 @@ #include "FirmwareBootType.h" #include "SemVer.h" #include "serialization/CallbackFn.h" -#include "StringView.h" #include "serialization/_fbs/HubToGatewayMessage_generated.h" +#include + namespace OpenShock::Serialization::Gateway { bool SerializeKeepAliveMessage(Common::SerializationCallbackFn callback); bool SerializeBootStatusMessage(int32_t otaUpdateId, OpenShock::FirmwareBootType bootType, const OpenShock::SemVer& version, Common::SerializationCallbackFn callback); bool SerializeOtaInstallStartedMessage(int32_t updateId, const OpenShock::SemVer& version, Common::SerializationCallbackFn callback); bool SerializeOtaInstallProgressMessage(int32_t updateId, Gateway::OtaInstallProgressTask task, float progress, Common::SerializationCallbackFn callback); - bool SerializeOtaInstallFailedMessage(int32_t updateId, StringView message, bool fatal, Common::SerializationCallbackFn callback); + bool SerializeOtaInstallFailedMessage(int32_t updateId, std::string_view message, bool fatal, Common::SerializationCallbackFn callback); } // namespace OpenShock::Serialization::Gateway diff --git a/include/util/PartitionUtils.h b/include/util/PartitionUtils.h index b99b7843..22669020 100644 --- a/include/util/PartitionUtils.h +++ b/include/util/PartitionUtils.h @@ -1,13 +1,12 @@ #pragma once -#include "StringView.h" - #include #include #include +#include namespace OpenShock { bool TryGetPartitionHash(const esp_partition_t* partition, char (&hash)[65]); - bool FlashPartitionFromUrl(const esp_partition_t* partition, StringView remoteUrl, const uint8_t (&remoteHash)[32], std::function progressCallback = nullptr); + bool FlashPartitionFromUrl(const esp_partition_t* partition, std::string_view remoteUrl, const uint8_t (&remoteHash)[32], std::function progressCallback = nullptr); } diff --git a/include/wifi/WiFiManager.h b/include/wifi/WiFiManager.h index 2fd67fe2..03f53d7b 100644 --- a/include/wifi/WiFiManager.h +++ b/include/wifi/WiFiManager.h @@ -1,10 +1,10 @@ #pragma once #include "wifi/WiFiNetwork.h" -#include "StringView.h" #include #include +#include #include namespace OpenShock::WiFiManager { @@ -16,7 +16,7 @@ namespace OpenShock::WiFiManager { /// @param ssid SSID of the network /// @param password Password of the network /// @return True if the network was saved successfully - bool Save(const char* ssid, StringView password); + bool Save(const char* ssid, std::string_view password); /// @brief Removes a network from the config by it's SSID /// @param ssid SSID of the network diff --git a/src/CaptivePortal.cpp b/src/CaptivePortal.cpp index ee70830b..2bd69753 100644 --- a/src/CaptivePortal.cpp +++ b/src/CaptivePortal.cpp @@ -144,7 +144,7 @@ void CaptivePortal::Update() { } } -bool CaptivePortal::SendMessageTXT(uint8_t socketId, StringView data) { +bool CaptivePortal::SendMessageTXT(uint8_t socketId, std::string_view data) { if (s_instance == nullptr) return false; s_instance->sendMessageTXT(socketId, data); @@ -159,7 +159,7 @@ bool CaptivePortal::SendMessageBIN(uint8_t socketId, const uint8_t* data, std::s return true; } -bool CaptivePortal::BroadcastMessageTXT(StringView data) { +bool CaptivePortal::BroadcastMessageTXT(std::string_view data) { if (s_instance == nullptr) return false; s_instance->broadcastMessageTXT(data); diff --git a/src/GatewayClient.cpp b/src/GatewayClient.cpp index 5315aec3..0d440ef2 100644 --- a/src/GatewayClient.cpp +++ b/src/GatewayClient.cpp @@ -64,7 +64,7 @@ void GatewayClient::disconnect() { m_webSocket.disconnect(); } -bool GatewayClient::sendMessageTXT(StringView data) { +bool GatewayClient::sendMessageTXT(std::string_view data) { if (m_state != State::Connected) { return false; } diff --git a/src/GatewayConnectionManager.cpp b/src/GatewayConnectionManager.cpp index b0943b36..e7fc531a 100644 --- a/src/GatewayConnectionManager.cpp +++ b/src/GatewayConnectionManager.cpp @@ -76,7 +76,7 @@ bool GatewayConnectionManager::IsLinked() { return (s_flags & FLAG_LINKED) != 0; } -AccountLinkResultCode GatewayConnectionManager::Link(StringView linkCode) { +AccountLinkResultCode GatewayConnectionManager::Link(std::string_view linkCode) { if ((s_flags & FLAG_HAS_IP) == 0) { return AccountLinkResultCode::NoInternetConnection; } @@ -109,9 +109,9 @@ AccountLinkResultCode GatewayConnectionManager::Link(StringView linkCode) { return AccountLinkResultCode::InternalError; } - StringView authToken = response.data.authToken; + std::string_view authToken = response.data.authToken; - if (authToken.isNullOrEmpty()) { + if (authToken.empty()) { ESP_LOGE(TAG, "Received empty auth token"); return AccountLinkResultCode::InternalError; } @@ -132,7 +132,7 @@ void GatewayConnectionManager::UnLink() { Config::ClearBackendAuthToken(); } -bool GatewayConnectionManager::SendMessageTXT(StringView data) { +bool GatewayConnectionManager::SendMessageTXT(std::string_view data) { if (s_wsClient == nullptr) { return false; } @@ -148,7 +148,7 @@ bool GatewayConnectionManager::SendMessageBIN(const uint8_t* data, std::size_t l return s_wsClient->sendMessageBIN(data, length); } -bool FetchDeviceInfo(StringView authToken) { +bool FetchDeviceInfo(std::string_view authToken) { // TODO: this function is very slow, should be optimized! if ((s_flags & FLAG_HAS_IP) == 0) { return false; diff --git a/src/OtaUpdateManager.cpp b/src/OtaUpdateManager.cpp index 07566958..759fa271 100644 --- a/src/OtaUpdateManager.cpp +++ b/src/OtaUpdateManager.cpp @@ -11,7 +11,6 @@ const char* const TAG = "OtaUpdateManager"; #include "Logging.h" #include "SemVer.h" #include "serialization/WSGateway.h" -#include "StringView.h" #include "Time.h" #include "util/HexUtils.h" #include "util/PartitionUtils.h" @@ -26,6 +25,7 @@ const char* const TAG = "OtaUpdateManager"; #include #include +#include #define OPENSHOCK_FW_CDN_CHANNEL_URL(ch) OPENSHOCK_FW_CDN_URL("/version-" ch ".txt") @@ -116,7 +116,7 @@ bool _sendProgressMessage(Serialization::Gateway::OtaInstallProgressTask task, f return true; } -bool _sendFailureMessage(StringView message, bool fatal = false) { +bool _sendFailureMessage(std::string_view message, bool fatal = false) { int32_t updateId; if (!Config::GetOtaUpdateId(updateId)) { ESP_LOGE(TAG, "Failed to get OTA update ID"); @@ -131,7 +131,7 @@ bool _sendFailureMessage(StringView message, bool fatal = false) { return true; } -bool _flashAppPartition(const esp_partition_t* partition, StringView remoteUrl, const uint8_t (&remoteHash)[32]) { +bool _flashAppPartition(const esp_partition_t* partition, std::string_view remoteUrl, const uint8_t (&remoteHash)[32]) { ESP_LOGD(TAG, "Flashing app partition"); if (!_sendProgressMessage(Serialization::Gateway::OtaInstallProgressTask::FlashingApplication, 0.0f)) { @@ -166,7 +166,7 @@ bool _flashAppPartition(const esp_partition_t* partition, StringView remoteUrl, return true; } -bool _flashFilesystemPartition(const esp_partition_t* parition, StringView remoteUrl, const uint8_t (&remoteHash)[32]) { +bool _flashFilesystemPartition(const esp_partition_t* parition, std::string_view remoteUrl, const uint8_t (&remoteHash)[32]) { if (!_sendProgressMessage(Serialization::Gateway::OtaInstallProgressTask::PreparingForInstall, 0.0f)) { return false; } @@ -393,7 +393,7 @@ void _otaUpdateTask(void* arg) { esp_restart(); } -bool _tryGetStringList(StringView url, std::vector& list) { +bool _tryGetStringList(std::string_view url, std::vector& list) { auto response = OpenShock::HTTP::GetString( url, { @@ -408,7 +408,7 @@ bool _tryGetStringList(StringView url, std::vector& list) { list.clear(); - OpenShock::StringView data = response.data; + std::string_view data = response.data; auto lines = data.splitLines(); list.reserve(lines.size()); @@ -416,7 +416,7 @@ bool _tryGetStringList(StringView url, std::vector& list) { for (auto line : lines) { line = line.trim(); - if (line.isNullOrEmpty()) { + if (line.empty()) { continue; } @@ -483,16 +483,16 @@ bool OtaUpdateManager::Init() { } bool OtaUpdateManager::TryGetFirmwareVersion(OtaUpdateChannel channel, OpenShock::SemVer& version) { - StringView channelIndexUrl; + std::string_view channelIndexUrl; switch (channel) { case OtaUpdateChannel::Stable: - channelIndexUrl = StringView(OPENSHOCK_FW_CDN_STABLE_URL); + channelIndexUrl = std::string_view(OPENSHOCK_FW_CDN_STABLE_URL); break; case OtaUpdateChannel::Beta: - channelIndexUrl = StringView(OPENSHOCK_FW_CDN_BETA_URL); + channelIndexUrl = std::string_view(OPENSHOCK_FW_CDN_BETA_URL); break; case OtaUpdateChannel::Develop: - channelIndexUrl = StringView(OPENSHOCK_FW_CDN_DEVELOP_URL); + channelIndexUrl = std::string_view(OPENSHOCK_FW_CDN_DEVELOP_URL); break; default: ESP_LOGE(TAG, "Unknown channel: %u", channel); @@ -538,7 +538,7 @@ bool OtaUpdateManager::TryGetFirmwareBoards(const OpenShock::SemVer& version, st return true; } -bool _tryParseIntoHash(StringView hash, uint8_t (&hashBytes)[32]) { +bool _tryParseIntoHash(std::string_view hash, uint8_t (&hashBytes)[32]) { if (!HexUtils::TryParseHex(hash.data(), hash.size(), hashBytes, 32)) { ESP_LOGE(TAG, "Failed to parse hash: %.*s", hash.size(), hash.data()); return false; @@ -580,11 +580,11 @@ bool OtaUpdateManager::TryGetFirmwareRelease(const OpenShock::SemVer& version, F return false; } - auto hashesLines = OpenShock::StringView(sha256HashesResponse.data).splitLines(); + auto hashesLines = std::string_view(sha256HashesResponse.data).splitLines(); // Parse hashes. bool foundAppHash = false, foundFilesystemHash = false; - for (OpenShock::StringView line : hashesLines) { + for (std::string_view line : hashesLines) { auto parts = line.splitWhitespace(); if (parts.size() != 2) { ESP_LOGE(TAG, "Invalid hashes entry: %.*s", line.size(), line.data()); diff --git a/src/SemVer.cpp b/src/SemVer.cpp index bdd2678a..162a90b8 100644 --- a/src/SemVer.cpp +++ b/src/SemVer.cpp @@ -15,8 +15,8 @@ constexpr bool _semverIsPositiveDigit(char c) { constexpr bool _semverIsDigit(char c) { return c == '0' || _semverIsPositiveDigit(c); } -constexpr bool _semverIsDigits(StringView str) { - if (str.isNullOrEmpty()) { +constexpr bool _semverIsDigits(std::string_view str) { + if (str.empty()) { return false; } @@ -34,8 +34,8 @@ constexpr bool _semverIsNonDigit(char c) { constexpr bool _semverIsIdentifierChararacter(char c) { return _semverIsDigit(c) || _semverIsNonDigit(c); } -constexpr bool _semverIsIdentifierChararacters(StringView str) { - if (str.isNullOrEmpty()) { +constexpr bool _semverIsIdentifierChararacters(std::string_view str) { + if (str.empty()) { return false; } @@ -47,8 +47,8 @@ constexpr bool _semverIsIdentifierChararacters(StringView str) { return true; } -constexpr bool _semverIsNumericIdentifier(StringView str) { - if (str.isNullOrEmpty()) { +constexpr bool _semverIsNumericIdentifier(std::string_view str) { + if (str.empty()) { return false; } @@ -58,8 +58,8 @@ constexpr bool _semverIsNumericIdentifier(StringView str) { return _semverIsPositiveDigit(str[0]) && _semverIsDigits(str.substr(1)); } -constexpr bool _semverIsAlphanumericIdentifier(StringView str) { - if (str.isNullOrEmpty()) { +constexpr bool _semverIsAlphanumericIdentifier(std::string_view str) { + if (str.empty()) { return false; } @@ -67,7 +67,7 @@ constexpr bool _semverIsAlphanumericIdentifier(StringView str) { return _semverIsNonDigit(str[0]); } - std::size_t nonDigitPos = StringView::npos; + std::size_t nonDigitPos = std::string_view::npos; for (std::size_t i = 0; i < str.length(); ++i) { if (_semverIsNonDigit(str[i])) { nonDigitPos = i; @@ -75,7 +75,7 @@ constexpr bool _semverIsAlphanumericIdentifier(StringView str) { } } - if (nonDigitPos == StringView::npos) { + if (nonDigitPos == std::string_view::npos) { return false; } @@ -93,19 +93,19 @@ constexpr bool _semverIsAlphanumericIdentifier(StringView str) { return _semverIsIdentifierChararacters(before) && _semverIsIdentifierChararacters(after); } -constexpr bool _semverIsBuildIdentifier(StringView str) { +constexpr bool _semverIsBuildIdentifier(std::string_view str) { return _semverIsAlphanumericIdentifier(str) || _semverIsDigits(str); } -constexpr bool _semverIsPrereleaseIdentifier(StringView str) { +constexpr bool _semverIsPrereleaseIdentifier(std::string_view str) { return _semverIsAlphanumericIdentifier(str) || _semverIsNumericIdentifier(str); } -constexpr bool _semverIsDotSeperatedBuildIdentifiers(StringView str) { - if (str.isNullOrEmpty()) { +constexpr bool _semverIsDotSeperatedBuildIdentifiers(std::string_view str) { + if (str.empty()) { return false; } auto dotIdx = str.find('.'); - while (dotIdx != StringView::npos) { + while (dotIdx != std::string_view::npos) { auto part = str.substr(0, dotIdx); if (!_semverIsBuildIdentifier(part)) { return false; @@ -117,13 +117,13 @@ constexpr bool _semverIsDotSeperatedBuildIdentifiers(StringView str) { return _semverIsBuildIdentifier(str); } -constexpr bool _semverIsDotSeperatedPreleaseIdentifiers(StringView str) { - if (str.isNullOrEmpty()) { +constexpr bool _semverIsDotSeperatedPreleaseIdentifiers(std::string_view str) { + if (str.empty()) { return false; } auto dotIdx = str.find('.'); - while (dotIdx != StringView::npos) { + while (dotIdx != std::string_view::npos) { auto part = str.substr(0, dotIdx); if (!_semverIsPrereleaseIdentifier(part)) { return false; @@ -139,9 +139,9 @@ const auto _semverIsPatch = _semverIsNumericIdentifier; const auto _semverIsMinor = _semverIsNumericIdentifier; const auto _semverIsMajor = _semverIsNumericIdentifier; const auto _semverIsPrerelease = _semverIsDotSeperatedPreleaseIdentifiers; -const auto _semverIsBuild = _semverIsDotSeperatedBuildIdentifiers; -bool _semverIsVersionCore(StringView str) { - if (str.isNullOrEmpty()) { +const auto _semverIsBuild = _semverIsDotSeperatedBuildIdentifiers; +bool _semverIsVersionCore(std::string_view str) { + if (str.empty()) { return false; } @@ -152,39 +152,39 @@ bool _semverIsVersionCore(StringView str) { return _semverIsMajor(parts[0]) && _semverIsMinor(parts[1]) && _semverIsPatch(parts[2]); } -bool _semverIsSemver(StringView str) { - if (str.isNullOrEmpty()) { +bool _semverIsSemver(std::string_view str) { + if (str.empty()) { return false; } auto dashPos = str.find('-'); auto plusPos = str.find('+'); - if (dashPos == StringView::npos && plusPos == StringView::npos) { + if (dashPos == std::string_view::npos && plusPos == std::string_view::npos) { return _semverIsVersionCore(str); } - if (dashPos != StringView::npos && plusPos != StringView::npos) { + if (dashPos != std::string_view::npos && plusPos != std::string_view::npos) { if (dashPos > plusPos) { return false; } - auto core = str.substr(0, dashPos); + auto core = str.substr(0, dashPos); auto prerelease = str.substr(dashPos + 1, plusPos - dashPos - 1); - auto build = str.substr(plusPos + 1); + auto build = str.substr(plusPos + 1); return _semverIsVersionCore(core) && _semverIsPrerelease(prerelease) && _semverIsBuild(build); } - if (dashPos != StringView::npos) { - auto core = str.substr(0, dashPos); + if (dashPos != std::string_view::npos) { + auto core = str.substr(0, dashPos); auto prerelease = str.substr(dashPos + 1); return _semverIsVersionCore(core) && _semverIsPrerelease(prerelease); } - if (plusPos != StringView::npos) { - auto core = str.substr(0, plusPos); + if (plusPos != std::string_view::npos) { + auto core = str.substr(0, plusPos); auto build = str.substr(plusPos + 1); return _semverIsVersionCore(core) && _semverIsBuild(build); @@ -193,8 +193,8 @@ bool _semverIsSemver(StringView str) { return false; } -bool _tryParseU16(OpenShock::StringView str, uint16_t& out) { - if (str.isNullOrEmpty()) { +bool _tryParseU16(std::string_view str, uint16_t& out) { + if (str.empty()) { return false; } @@ -252,24 +252,24 @@ std::string SemVer::toString() const { return str; } -bool OpenShock::TryParseSemVer(StringView semverStr, SemVer& semver) { +bool OpenShock::TryParseSemVer(std::string_view semverStr, SemVer& semver) { auto parts = semverStr.split('.'); if (parts.size() < 3) { ESP_LOGE(TAG, "Must have at least 3 parts: %.*s", semverStr.length(), semverStr.data()); return false; } - StringView majorStr = parts[0], minorStr = parts[1], patchStr = parts[2]; + std::string_view majorStr = parts[0], minorStr = parts[1], patchStr = parts[2]; auto dashIdx = patchStr.find('-'); - if (dashIdx != StringView::npos) { + if (dashIdx != std::string_view::npos) { semver.prerelease = patchStr.substr(dashIdx + 1); patchStr = patchStr.substr(0, dashIdx); } auto plusIdx = semver.prerelease.find('+'); - if (plusIdx != StringView::npos) { - semver.build = semver.prerelease.substr(plusIdx + 1); + if (plusIdx != std::string_view::npos) { + semver.build = semver.prerelease.substr(plusIdx + 1); semver.prerelease = semver.prerelease.substr(0, plusIdx); } diff --git a/src/config/BackendConfig.cpp b/src/config/BackendConfig.cpp index f0084640..a9569873 100644 --- a/src/config/BackendConfig.cpp +++ b/src/config/BackendConfig.cpp @@ -9,7 +9,7 @@ using namespace OpenShock::Config; BackendConfig::BackendConfig() : domain(OPENSHOCK_API_DOMAIN), authToken(), lcgOverride() { } -BackendConfig::BackendConfig(StringView domain, StringView authToken, StringView lcgOverride) : domain(domain.toString()), authToken(authToken.toString()), lcgOverride(lcgOverride.toString()) { } +BackendConfig::BackendConfig(std::string_view domain, std::string_view authToken, std::string_view lcgOverride) : domain(std::string(domain)), authToken(std::string(authToken)), lcgOverride(std::string(lcgOverride)) { } void BackendConfig::ToDefault() { domain = OPENSHOCK_API_DOMAIN; diff --git a/src/config/Config.cpp b/src/config/Config.cpp index c91d9739..c5326d70 100644 --- a/src/config/Config.cpp +++ b/src/config/Config.cpp @@ -167,7 +167,7 @@ std::string Config::GetAsJSON(bool withSensitiveData) { return result; } -bool Config::SaveFromJSON(StringView json) { +bool Config::SaveFromJSON(std::string_view json) { cJSON* root = cJSON_ParseWithLength(json.data(), json.size()); if (root == nullptr) { ESP_LOGE(TAG, "Failed to parse JSON: %s", cJSON_GetErrorPtr()); @@ -383,7 +383,7 @@ bool Config::AnyWiFiCredentials(std::function& credentialsList) : accessPointSSID(accessPointSSID.toString()), hostname(hostname.toString()), credentialsList(credentialsList) { } +WiFiConfig::WiFiConfig(std::string_view accessPointSSID, std::string_view hostname, const std::vector& credentialsList) : accessPointSSID(accessPointSSID.toString()), hostname(hostname.toString()), credentialsList(credentialsList) { } void WiFiConfig::ToDefault() { accessPointSSID = OPENSHOCK_FW_AP_PREFIX; diff --git a/src/config/WiFiCredentials.cpp b/src/config/WiFiCredentials.cpp index 39561194..f152fe8d 100644 --- a/src/config/WiFiCredentials.cpp +++ b/src/config/WiFiCredentials.cpp @@ -10,7 +10,7 @@ using namespace OpenShock::Config; WiFiCredentials::WiFiCredentials() : id(0), ssid(), password() { } -WiFiCredentials::WiFiCredentials(uint8_t id, StringView ssid, StringView password) : id(id), ssid(ssid.toString()), password(password.toString()) { } +WiFiCredentials::WiFiCredentials(uint8_t id, std::string_view ssid, std::string_view password) : id(id), ssid(ssid.toString()), password(password.toString()) { } void WiFiCredentials::ToDefault() { id = 0; diff --git a/src/event_handlers/websocket/gateway/OtaInstall.cpp b/src/event_handlers/websocket/gateway/OtaInstall.cpp index 9b397e10..8a032dc2 100644 --- a/src/event_handlers/websocket/gateway/OtaInstall.cpp +++ b/src/event_handlers/websocket/gateway/OtaInstall.cpp @@ -23,12 +23,12 @@ void _Private::HandleOtaInstall(const OpenShock::Serialization::Gateway::Gateway return; } - StringView prerelease, build; + std::string_view prerelease, build; if (semver->prerelease() != nullptr) { - prerelease = StringView(semver->prerelease()->c_str(), semver->prerelease()->size()); + prerelease = std::string_view(semver->prerelease()->c_str(), semver->prerelease()->size()); } if (semver->build() != nullptr) { - build = StringView(semver->build()->c_str(), semver->build()->size()); + build = std::string_view(semver->build()->c_str(), semver->build()->size()); } OpenShock::SemVer version(semver->major(), semver->minor(), semver->patch(), prerelease, build); diff --git a/src/http/HTTPRequestManager.cpp b/src/http/HTTPRequestManager.cpp index 26726efd..c8906d75 100644 --- a/src/http/HTTPRequestManager.cpp +++ b/src/http/HTTPRequestManager.cpp @@ -102,9 +102,9 @@ std::unordered_map> s_rateLimits; using namespace OpenShock; -StringView _getDomain(StringView url) { - if (url.isNullOrEmpty()) { - return StringView::Null(); +std::string_view _getDomain(std::string_view url) { + if (url.empty()) { + return std::string_view::Null(); } // Remove the protocol, port, and path eg. "https://api.example.com:443/path" -> "api.example.com" @@ -112,18 +112,18 @@ StringView _getDomain(StringView url) { // Remove all subdomains eg. "api.example.com" -> "example.com" auto domainSep = url.rfind('.'); - if (domainSep == StringView::npos) { + if (domainSep == std::string_view::npos) { return url; // E.g. "localhost" } domainSep = url.rfind('.', domainSep - 1); - if (domainSep != StringView::npos) { + if (domainSep != std::string_view::npos) { url = url.substr(domainSep + 1); } return url; } -std::shared_ptr _rateLimitFactory(StringView domain) { +std::shared_ptr _rateLimitFactory(std::string_view domain) { auto rateLimit = std::make_shared(); // Add default limits @@ -139,7 +139,7 @@ std::shared_ptr _rateLimitFactory(StringView domain) { return rateLimit; } -std::shared_ptr _getRateLimiter(StringView url) { +std::shared_ptr _getRateLimiter(std::string_view url) { auto domain = _getDomain(url).toString(); if (domain.empty()) { return nullptr; @@ -185,8 +185,8 @@ constexpr bool _tryFindCRLF(std::size_t& pos, const uint8_t* buffer, std::size_t return false; } -constexpr bool _tryParseHexSizeT(std::size_t& result, StringView str) { - if (str.isNullOrEmpty() || str.size() > sizeof(std::size_t) * 2) { +constexpr bool _tryParseHexSizeT(std::size_t& result, std::string_view str) { + if (str.empty() || str.size() > sizeof(std::size_t) * 2) { return false; } @@ -244,7 +244,7 @@ ParserState _parseChunkHeader(const uint8_t* buffer, std::size_t bufferLen, std: return ParserState::Invalid; } - StringView sizeField(reinterpret_cast(buffer), sizeFieldEnd); + std::string_view sizeField(reinterpret_cast(buffer), sizeFieldEnd); // Parse the chunk size if (!_tryParseHexSizeT(payloadLen, sizeField)) { @@ -422,7 +422,7 @@ StreamReaderResult _readStreamData(HTTPClient& client, WiFiClient* stream, std:: HTTP::Response _doGetStream( HTTPClient& client, - StringView url, + std::string_view url, const std::map& headers, const std::vector& acceptedCodes, std::shared_ptr rateLimiter, @@ -516,7 +516,7 @@ HTTP::Response _doGetStream( } HTTP::Response - HTTP::Download(StringView url, const std::map& headers, HTTP::GotContentLengthCallback contentLengthCallback, HTTP::DownloadCallback downloadCallback, const std::vector& acceptedCodes, uint32_t timeoutMs) { + HTTP::Download(std::string_view url, const std::map& headers, HTTP::GotContentLengthCallback contentLengthCallback, HTTP::DownloadCallback downloadCallback, const std::vector& acceptedCodes, uint32_t timeoutMs) { std::shared_ptr rateLimiter = _getRateLimiter(url); if (rateLimiter == nullptr) { return {RequestResult::InvalidURL, 0, 0}; @@ -532,7 +532,7 @@ HTTP::Response return _doGetStream(client, url, headers, acceptedCodes, rateLimiter, contentLengthCallback, downloadCallback, timeoutMs); } -HTTP::Response HTTP::GetString(StringView url, const std::map& headers, const std::vector& acceptedCodes, uint32_t timeoutMs) { +HTTP::Response HTTP::GetString(std::string_view url, const std::map& headers, const std::vector& acceptedCodes, uint32_t timeoutMs) { std::string result; auto allocator = [&result](std::size_t contentLength) { diff --git a/src/http/JsonAPI.cpp b/src/http/JsonAPI.cpp index fd6e2c83..de77dde3 100644 --- a/src/http/JsonAPI.cpp +++ b/src/http/JsonAPI.cpp @@ -5,14 +5,14 @@ using namespace OpenShock; -HTTP::Response HTTP::JsonAPI::LinkAccount(const char* accountLinkCode) { +HTTP::Response HTTP::JsonAPI::LinkAccount(std::string_view accountLinkCode) { std::string domain; if (!Config::GetBackendDomain(domain)) { return {HTTP::RequestResult::InternalError, 0, {}}; } char uri[OPENSHOCK_URI_BUFFER_SIZE]; - sprintf(uri, "https://%s/1/device/pair/%s", domain.c_str(), accountLinkCode); + sprintf(uri, "https://%s/1/device/pair/%.*s", domain.c_str(), accountLinkCode.length(), accountLinkCode.data()); return HTTP::GetJSON( uri, @@ -24,7 +24,7 @@ HTTP::Response HTTP::JsonAPI::LinkA ); } -HTTP::Response HTTP::JsonAPI::GetDeviceInfo(StringView deviceToken) { +HTTP::Response HTTP::JsonAPI::GetDeviceInfo(std::string_view deviceToken) { std::string domain; if (!Config::GetBackendDomain(domain)) { return {HTTP::RequestResult::InternalError, 0, {}}; @@ -44,7 +44,7 @@ HTTP::Response HTTP::JsonAPI::GetDev ); } -HTTP::Response HTTP::JsonAPI::AssignLcg(StringView deviceToken) { +HTTP::Response HTTP::JsonAPI::AssignLcg(std::string_view deviceToken) { std::string domain; if (!Config::GetBackendDomain(domain)) { return {HTTP::RequestResult::InternalError, 0, {}}; diff --git a/src/intconv.cpp b/src/intconv.cpp index 3859b77f..b6856e56 100644 --- a/src/intconv.cpp +++ b/src/intconv.cpp @@ -20,7 +20,7 @@ constexpr unsigned int NumDigits() { // Base converter template -constexpr bool spanToT(OpenShock::StringView str, T& val) { +constexpr bool spanToT(std::string_view str, T& val) { static_assert(std::is_integral::value); const T Threshold = std::numeric_limits::max() / 10; @@ -55,10 +55,10 @@ constexpr bool spanToT(OpenShock::StringView str, T& val) { // Unsigned converter template -constexpr bool spanToUT(OpenShock::StringView str, T& val) { +constexpr bool spanToUT(std::string_view str, T& val) { static_assert(std::is_unsigned::value); - if (str.isNullOrEmpty() || str.length() > NumDigits()) { + if (str.empty() || str.length() > NumDigits()) { return false; } @@ -67,17 +67,17 @@ constexpr bool spanToUT(OpenShock::StringView str, T& val) { // Signed converter template -constexpr bool spanToST(OpenShock::StringView str, T& val) { +constexpr bool spanToST(std::string_view str, T& val) { static_assert(std::is_signed::value); - if (str.isNullOrEmpty() || str.length() > NumDigits()) { + if (str.empty() || str.length() > NumDigits()) { return false; } bool negative = str.front() == '-'; if (negative) { str = str.substr(1); - if (str.isNullOrEmpty()) { + if (str.empty()) { return false; } } @@ -99,28 +99,28 @@ constexpr bool spanToST(OpenShock::StringView str, T& val) { using namespace OpenShock; // Specific converters -bool IntConv::stoi8(OpenShock::StringView str, int8_t& val) { +bool IntConv::stoi8(std::string_view str, int8_t& val) { return spanToST(str, val); } -bool IntConv::stou8(OpenShock::StringView str, uint8_t& val) { +bool IntConv::stou8(std::string_view str, uint8_t& val) { return spanToUT(str, val); } -bool IntConv::stoi16(OpenShock::StringView str, int16_t& val) { +bool IntConv::stoi16(std::string_view str, int16_t& val) { return spanToST(str, val); } -bool IntConv::stou16(OpenShock::StringView str, uint16_t& val) { +bool IntConv::stou16(std::string_view str, uint16_t& val) { return spanToUT(str, val); } -bool IntConv::stoi32(OpenShock::StringView str, int32_t& val) { +bool IntConv::stoi32(std::string_view str, int32_t& val) { return spanToST(str, val); } -bool IntConv::stou32(OpenShock::StringView str, uint32_t& val) { +bool IntConv::stou32(std::string_view str, uint32_t& val) { return spanToUT(str, val); } -bool IntConv::stoi64(OpenShock::StringView str, int64_t& val) { +bool IntConv::stoi64(std::string_view str, int64_t& val) { return spanToST(str, val); } -bool IntConv::stou64(OpenShock::StringView str, uint64_t& val) { +bool IntConv::stou64(std::string_view str, uint64_t& val) { return spanToUT(str, val); } diff --git a/src/serial/SerialInputHandler.cpp b/src/serial/SerialInputHandler.cpp index 52b022ac..9bbe01a2 100644 --- a/src/serial/SerialInputHandler.cpp +++ b/src/serial/SerialInputHandler.cpp @@ -12,7 +12,6 @@ const char* const TAG = "SerialInputHandler"; #include "Logging.h" #include "serialization/JsonAPI.h" #include "serialization/JsonSerial.h" -#include "StringView.h" #include "Time.h" #include "util/Base64Utils.h" #include "wifi/WiFiManager.h" @@ -20,9 +19,9 @@ const char* const TAG = "SerialInputHandler"; #include #include -#include - #include +#include +#include #define SERPR_SYS(format, ...) Serial.printf("$SYS$|" format "\n", ##__VA_ARGS__) #define SERPR_RESPONSE(format, ...) SERPR_SYS("Response|" format, ##__VA_ARGS__) @@ -35,21 +34,21 @@ const int64_t PASTE_INTERVAL_THRESHOLD_MS = 20; const std::size_t SERIAL_BUFFER_CLEAR_THRESHOLD = 512; struct SerialCmdHandler { - StringView cmd; + std::string_view cmd; const char* helpResponse; - void (*commandHandler)(StringView); + void (*commandHandler)(std::string_view); }; static bool s_echoEnabled = true; -static std::unordered_map s_commandHandlers; +static std::unordered_map s_commandHandlers; /// @brief Tries to parse a boolean from a string (case-insensitive) /// @param str Input string /// @param strLen Length of input string /// @param out Output boolean /// @return True if the argument is a boolean, false otherwise -bool _tryParseBool(StringView str, bool& out) { - if (str.isNullOrEmpty()) { +bool _tryParseBool(std::string_view str, bool& out) { + if (str.empty()) { return false; } @@ -72,21 +71,21 @@ bool _tryParseBool(StringView str, bool& out) { return false; } -void _handleVersionCommand(StringView arg) { +void _handleVersionCommand(std::string_view arg) { (void)arg; Serial.print("\n"); SerialInputHandler::PrintVersionInfo(); } -void _handleRestartCommand(StringView arg) { +void _handleRestartCommand(std::string_view arg) { (void)arg; Serial.println("Restarting ESP..."); ESP.restart(); } -void _handleFactoryResetCommand(StringView arg) { +void _handleFactoryResetCommand(std::string_view arg) { (void)arg; Serial.println("Resetting to factory defaults..."); @@ -95,8 +94,8 @@ void _handleFactoryResetCommand(StringView arg) { ESP.restart(); } -void _handleRfTxPinCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleRfTxPinCommand(std::string_view arg) { + if (arg.empty()) { uint8_t txPin; if (!Config::GetRFConfigTxPin(txPin)) { SERPR_ERROR("Failed to get RF TX pin from config"); @@ -134,8 +133,8 @@ void _handleRfTxPinCommand(StringView arg) { } } -void _handleDomainCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleDomainCommand(std::string_view arg) { + if (arg.empty()) { std::string domain; if (!Config::GetBackendDomain(domain)) { SERPR_ERROR("Failed to get domain from config"); @@ -194,8 +193,8 @@ void _handleDomainCommand(StringView arg) { ESP.restart(); } -void _handleAuthtokenCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleAuthtokenCommand(std::string_view arg) { + if (arg.empty()) { std::string authToken; if (!Config::GetBackendAuthToken(authToken)) { SERPR_ERROR("Failed to get auth token from config"); @@ -216,8 +215,8 @@ void _handleAuthtokenCommand(StringView arg) { } } -void _handleLcgOverrideCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleLcgOverrideCommand(std::string_view arg) { + if (arg.empty()) { std::string lcgOverride; if (!Config::GetBackendLCGOverride(lcgOverride)) { SERPR_ERROR("Failed to get LCG override from config"); @@ -250,7 +249,7 @@ void _handleLcgOverrideCommand(StringView arg) { return; } - StringView domain = arg.substr(4); + std::string_view domain = arg.substr(4); if (domain.size() + 40 >= OPENSHOCK_URI_BUFFER_SIZE) { SERPR_ERROR("Domain name too long, please try increasing the \"OPENSHOCK_URI_BUFFER_SIZE\" constant in source code"); @@ -299,10 +298,10 @@ void _handleLcgOverrideCommand(StringView arg) { SERPR_ERROR("Invalid subcommand"); } -void _handleNetworksCommand(StringView arg) { +void _handleNetworksCommand(std::string_view arg) { cJSON* root; - if (arg.isNullOrEmpty()) { + if (arg.empty()) { root = cJSON_CreateArray(); if (root == nullptr) { SERPR_ERROR("Failed to create JSON array"); @@ -368,10 +367,10 @@ void _handleNetworksCommand(StringView arg) { OpenShock::WiFiManager::RefreshNetworkCredentials(); } -void _handleKeepAliveCommand(StringView arg) { +void _handleKeepAliveCommand(std::string_view arg) { bool keepAliveEnabled; - if (arg.isNullOrEmpty()) { + if (arg.empty()) { // Get keep alive status if (!Config::GetRFConfigKeepAliveEnabled(keepAliveEnabled)) { SERPR_ERROR("Failed to get keep-alive status from config"); @@ -396,8 +395,8 @@ void _handleKeepAliveCommand(StringView arg) { } } -void _handleSerialEchoCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleSerialEchoCommand(std::string_view arg) { + if (arg.empty()) { // Get current serial echo status SERPR_RESPONSE("SerialEcho|%s", s_echoEnabled ? "true" : "false"); return; @@ -419,8 +418,8 @@ void _handleSerialEchoCommand(StringView arg) { } } -void _handleValidGpiosCommand(StringView arg) { - if (!arg.isNullOrEmpty()) { +void _handleValidGpiosCommand(std::string_view arg) { + if (!arg.empty()) { SERPR_ERROR("Invalid argument (too many arguments)"); return; } @@ -444,8 +443,8 @@ void _handleValidGpiosCommand(StringView arg) { SERPR_RESPONSE("ValidGPIOs|%s", buffer.c_str()); } -void _handleJsonConfigCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleJsonConfigCommand(std::string_view arg) { + if (arg.empty()) { // Get raw config std::string json = Config::GetAsJSON(true); @@ -463,8 +462,8 @@ void _handleJsonConfigCommand(StringView arg) { ESP.restart(); } -void _handleRawConfigCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleRawConfigCommand(std::string_view arg) { + if (arg.empty()) { std::vector buffer; // Get raw config @@ -499,7 +498,7 @@ void _handleRawConfigCommand(StringView arg) { ESP.restart(); } -void _handleDebugInfoCommand(StringView arg) { +void _handleDebugInfoCommand(std::string_view arg) { (void)arg; SERPR_RESPONSE("RTOSInfo|Free Heap|%u", xPortGetFreeHeapSize()); @@ -529,8 +528,8 @@ void _handleDebugInfoCommand(StringView arg) { } } -void _handleRFTransmitCommand(StringView arg) { - if (arg.isNullOrEmpty()) { +void _handleRFTransmitCommand(std::string_view arg) { + if (arg.empty()) { SERPR_ERROR("No command"); return; } @@ -558,9 +557,9 @@ void _handleRFTransmitCommand(StringView arg) { SERPR_SUCCESS("Command sent"); } -void _handleHelpCommand(StringView arg) { +void _handleHelpCommand(std::string_view arg) { arg = arg.trim(); - if (arg.isNullOrEmpty()) { + if (arg.empty()) { SerialInputHandler::PrintWelcomeHeader(); // Raw string literal (1+ to remove the first newline) @@ -853,16 +852,16 @@ int findLineStart(const char* buffer, int bufferSize, int lineEnd) { return -1; } -void processSerialLine(StringView line) { +void processSerialLine(std::string_view line) { line = line.trim(); - if (line.isNullOrEmpty()) { + if (line.empty()) { SERPR_ERROR("No command"); return; } - auto parts = line.split(' ', 1); - StringView command = parts[0]; - StringView arguments = parts.size() > 1 ? parts[1] : StringView(); + auto parts = line.split(' ', 1); + std::string_view command = parts[0]; + std::string_view arguments = parts.size() > 1 ? parts[1] : std::string_view(); auto it = s_commandHandlers.find(command); if (it == s_commandHandlers.end()) { @@ -981,7 +980,7 @@ void SerialInputHandler::Update() { break; } - StringView line = StringView(buffer, lineEnd).trim(); + std::string_view line = std::string_view(buffer, lineEnd).trim(); Serial.printf("\r> %.*s\n", line.size(), line.data()); diff --git a/src/serialization/WSGateway.cpp b/src/serialization/WSGateway.cpp index 98911bc6..7b469200 100644 --- a/src/serialization/WSGateway.cpp +++ b/src/serialization/WSGateway.cpp @@ -75,7 +75,7 @@ bool Gateway::SerializeOtaInstallProgressMessage(int32_t updateId, Gateway::OtaI return callback(span.data(), span.size()); } -bool Gateway::SerializeOtaInstallFailedMessage(int32_t updateId, StringView message, bool fatal, Common::SerializationCallbackFn callback) { +bool Gateway::SerializeOtaInstallFailedMessage(int32_t updateId, std::string_view message, bool fatal, Common::SerializationCallbackFn callback) { flatbuffers::FlatBufferBuilder builder(256); // TODO: Profile this and adjust the size accordingly auto messageOffset = builder.CreateString(message.data(), message.size()); diff --git a/src/util/ParitionUtils.cpp b/src/util/ParitionUtils.cpp index da969b9b..5df8da87 100644 --- a/src/util/ParitionUtils.cpp +++ b/src/util/ParitionUtils.cpp @@ -22,7 +22,7 @@ bool OpenShock::TryGetPartitionHash(const esp_partition_t* partition, char (&has return true; } -bool OpenShock::FlashPartitionFromUrl(const esp_partition_t* partition, StringView remoteUrl, const uint8_t (&remoteHash)[32], std::function progressCallback) { +bool OpenShock::FlashPartitionFromUrl(const esp_partition_t* partition, std::string_view remoteUrl, const uint8_t (&remoteHash)[32], std::function progressCallback) { OpenShock::SHA256 sha256; if (!sha256.begin()) { ESP_LOGE(TAG, "Failed to initialize SHA256 hash"); diff --git a/src/wifi/WiFiManager.cpp b/src/wifi/WiFiManager.cpp index 98c4236e..1d217a33 100644 --- a/src/wifi/WiFiManager.cpp +++ b/src/wifi/WiFiManager.cpp @@ -171,7 +171,7 @@ bool _connect(const uint8_t (&bssid)[6], const std::string& password) { return _connectImpl(it->ssid, password.c_str(), bssid); } -bool _authenticate(const WiFiNetwork& net, StringView password) { +bool _authenticate(const WiFiNetwork& net, std::string_view password) { uint8_t id = Config::AddWiFiCredentials(net.ssid, password); if (id == 0) { Serialization::Local::SerializeErrorMessage("too_many_credentials", CaptivePortal::BroadcastMessageBIN); @@ -342,7 +342,7 @@ bool WiFiManager::Init() { return true; } -bool WiFiManager::Save(const char* ssid, StringView password) { +bool WiFiManager::Save(const char* ssid, std::string_view password) { ESP_LOGV(TAG, "Authenticating to network %s", ssid); auto it = _findNetworkBySSID(ssid); From 8767bfbd75605a30227562c0c65329b5980f1871 Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 6 Sep 2024 11:31:21 +0200 Subject: [PATCH 2/6] Fix the rest of the problems --- include/Common.h | 4 +- include/SemVer.h | 4 +- include/util/StringUtils.h | 104 +++++++++++++++++++++++++++++- src/EStopManager.cpp | 1 + src/OtaUpdateManager.cpp | 36 ++++++----- src/SemVer.cpp | 5 +- src/config/WiFiConfig.cpp | 2 +- src/config/WiFiCredentials.cpp | 2 +- src/http/HTTPRequestManager.cpp | 41 ++++++++---- src/http/JsonAPI.cpp | 5 +- src/intconv.cpp | 57 ++++++++-------- src/serial/SerialInputHandler.cpp | 88 +++++++++++++++---------- src/wifi/WiFiManager.cpp | 2 +- 13 files changed, 247 insertions(+), 104 deletions(-) diff --git a/include/Common.h b/include/Common.h index 0b5e07e5..e4c67de0 100644 --- a/include/Common.h +++ b/include/Common.h @@ -10,7 +10,6 @@ TypeName(TypeName&&) = delete; \ void operator=(TypeName&&) = delete - #ifndef OPENSHOCK_API_DOMAIN #error "OPENSHOCK_API_DOMAIN must be defined" #endif @@ -59,6 +58,5 @@ #endif namespace OpenShock::Constants { - const char* const FW_USERAGENT = OPENSHOCK_FW_USERAGENT; - const std::string_view FW_USERAGENT_sv = OPENSHOCK_FW_USERAGENT ""_sv; + const char* const FW_USERAGENT = OPENSHOCK_FW_USERAGENT; } // namespace OpenShock::Constants diff --git a/include/SemVer.h b/include/SemVer.h index f58bb3e1..24805232 100644 --- a/include/SemVer.h +++ b/include/SemVer.h @@ -16,8 +16,8 @@ namespace OpenShock { SemVer(uint16_t major, uint16_t minor, uint16_t patch) : major(major), minor(minor), patch(patch), prerelease(), build() {} - SemVer(uint16_t major, uint16_t minor, uint16_t patch, StringView prerelease, StringView build) - : major(major), minor(minor), patch(patch), prerelease(prerelease.toString()), build(build.toString()) + SemVer(uint16_t major, uint16_t minor, uint16_t patch, std::string_view prerelease, std::string_view build) + : major(major), minor(minor), patch(patch), prerelease(std::string(prerelease)), build(std::string(build)) {} bool operator==(const SemVer& other) const { diff --git a/include/util/StringUtils.h b/include/util/StringUtils.h index 1b2cc8c0..1f6db043 100644 --- a/include/util/StringUtils.h +++ b/include/util/StringUtils.h @@ -1,8 +1,108 @@ #pragma once -#include +#include + #include +#include +#include +#include +#include namespace OpenShock { bool FormatToString(std::string& out, const char* format, ...); -} // namespace OpenShock + + inline std::vector StringSplit(const std::string_view view, char delimiter, std::size_t maxSplits = std::numeric_limits::max()) { + if (view.empty()) { + return {}; + } + + std::vector result = {}; + + std::size_t pos = 0; + std::size_t splits = 0; + while (pos < view.size() && splits < maxSplits) { + std::size_t nextPos = view.find(delimiter, pos); + if (nextPos == std::string_view::npos) { + nextPos = view.size(); + } + + result.push_back(view.substr(pos, nextPos - pos)); + pos = nextPos + 1; + ++splits; + } + + if (pos < view.size()) { + result.push_back(view.substr(pos)); + } + + return result; + } + inline std::vector StringSplit(const std::string_view view, bool (*predicate)(char delimiter), std::size_t maxSplits = std::numeric_limits::max()) { + if (view.empty()) { + return {}; + } + + std::vector result = {}; + + const char* start = nullptr; + for (const char* ptr = view.begin(); ptr < view.end(); ++ptr) { + if (predicate(*ptr)) { + if (start != nullptr) { + result.emplace_back(std::string_view(start, ptr - start)); + start = nullptr; + } + } else if (start == nullptr) { + start = ptr; + } + } + + if (start != nullptr) { + result.emplace_back(std::string_view(start, view.end() - start)); + } + + return result; + } + inline std::vector StringSplitNewLines(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()) { + return StringSplit( + view, [](char c) { return c == '\r' || c == '\n'; }, maxSplits + ); + } + inline std::vector StringSplitWhiteSpace(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()) { + return StringSplit( + view, [](char c) { return isspace(c) != 0; }, maxSplits + ); + } + constexpr std::string_view StringTrimLeft(std::string_view view) { + if (view.empty()) { + return view; + } + + std::size_t pos = 0; + while (pos < view.size() && isspace(view[pos])) { + ++pos; + } + + return view.substr(pos); + } + constexpr std::string_view StringTrimRight(std::string_view view) { + if (view.empty()) { + return view; + } + + std::size_t pos = view.size() - 1; + while (pos > 0 && isspace(view[pos])) { + --pos; + } + + return view.substr(0, pos + 1); + } + constexpr std::string_view StringTrim(std::string_view view) { + return StringTrimLeft(StringTrimRight(view)); + } + constexpr bool StringStartsWith(std::string_view view, std::string_view prefix) { + return view.size() >= prefix.size() && view.substr(0, prefix.size()) == prefix; + } + inline String StringToArduinoString(std::string_view view) { + return String(view.data(), view.size()); + } +} // namespace OpenShock diff --git a/src/EStopManager.cpp b/src/EStopManager.cpp index 7eb8130f..f5f48b08 100644 --- a/src/EStopManager.cpp +++ b/src/EStopManager.cpp @@ -11,6 +11,7 @@ const char* const TAG = "EStopManager"; #include "VisualStateManager.h" #include +#include #include using namespace OpenShock; diff --git a/src/OtaUpdateManager.cpp b/src/OtaUpdateManager.cpp index 759fa271..65a26391 100644 --- a/src/OtaUpdateManager.cpp +++ b/src/OtaUpdateManager.cpp @@ -27,6 +27,8 @@ const char* const TAG = "OtaUpdateManager"; #include #include +using namespace std::string_view_literals; + #define OPENSHOCK_FW_CDN_CHANNEL_URL(ch) OPENSHOCK_FW_CDN_URL("/version-" ch ".txt") #define OPENSHOCK_FW_CDN_STABLE_URL OPENSHOCK_FW_CDN_CHANNEL_URL("stable") @@ -148,7 +150,7 @@ bool _flashAppPartition(const esp_partition_t* partition, std::string_view remot if (!OpenShock::FlashPartitionFromUrl(partition, remoteUrl, remoteHash, onProgress)) { ESP_LOGE(TAG, "Failed to flash app partition"); - _sendFailureMessage("Failed to flash app partition"_sv); + _sendFailureMessage("Failed to flash app partition"sv); return false; } @@ -159,7 +161,7 @@ bool _flashAppPartition(const esp_partition_t* partition, std::string_view remot // Set app partition bootable. if (esp_ota_set_boot_partition(partition) != ESP_OK) { ESP_LOGE(TAG, "Failed to set app partition bootable"); - _sendFailureMessage("Failed to set app partition bootable"_sv); + _sendFailureMessage("Failed to set app partition bootable"sv); return false; } @@ -174,7 +176,7 @@ bool _flashFilesystemPartition(const esp_partition_t* parition, std::string_view // Make sure captive portal is stopped, timeout after 5 seconds. if (!CaptivePortal::ForceClose(5000U)) { ESP_LOGE(TAG, "Failed to force close captive portal (timed out)"); - _sendFailureMessage("Failed to force close captive portal (timed out)"_sv); + _sendFailureMessage("Failed to force close captive portal (timed out)"sv); return false; } @@ -194,7 +196,7 @@ bool _flashFilesystemPartition(const esp_partition_t* parition, std::string_view if (!OpenShock::FlashPartitionFromUrl(parition, remoteUrl, remoteHash, onProgress)) { ESP_LOGE(TAG, "Failed to flash filesystem partition"); - _sendFailureMessage("Failed to flash filesystem partition"_sv); + _sendFailureMessage("Failed to flash filesystem partition"sv); return false; } @@ -206,7 +208,7 @@ bool _flashFilesystemPartition(const esp_partition_t* parition, std::string_view fs::LittleFSFS test; if (!test.begin(false, "/static", 10, "static0")) { ESP_LOGE(TAG, "Failed to mount filesystem"); - _sendFailureMessage("Failed to mount filesystem"_sv); + _sendFailureMessage("Failed to mount filesystem"sv); return false; } test.end(); @@ -334,7 +336,7 @@ void _otaUpdateTask(void* arg) { OtaUpdateManager::FirmwareRelease release; if (!OtaUpdateManager::TryGetFirmwareRelease(version, release)) { ESP_LOGE(TAG, "Failed to fetch firmware release"); // TODO: Send error message to server - _sendFailureMessage("Failed to fetch firmware release"_sv); + _sendFailureMessage("Failed to fetch firmware release"sv); continue; } @@ -350,7 +352,7 @@ void _otaUpdateTask(void* arg) { const esp_partition_t* appPartition = esp_ota_get_next_update_partition(nullptr); if (appPartition == nullptr) { ESP_LOGE(TAG, "Failed to get app update partition"); // TODO: Send error message to server - _sendFailureMessage("Failed to get app update partition"_sv); + _sendFailureMessage("Failed to get app update partition"sv); continue; } @@ -358,7 +360,7 @@ void _otaUpdateTask(void* arg) { const esp_partition_t* filesystemPartition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "static0"); if (filesystemPartition == nullptr) { ESP_LOGE(TAG, "Failed to find filesystem partition"); // TODO: Send error message to server - _sendFailureMessage("Failed to find filesystem partition"_sv); + _sendFailureMessage("Failed to find filesystem partition"sv); continue; } @@ -373,7 +375,7 @@ void _otaUpdateTask(void* arg) { // Set OTA boot type in config. if (!Config::SetOtaUpdateStep(OpenShock::OtaUpdateStep::Updated)) { ESP_LOGE(TAG, "Failed to set OTA update step"); - _sendFailureMessage("Failed to set OTA update step"_sv); + _sendFailureMessage("Failed to set OTA update step"sv); continue; } @@ -410,17 +412,17 @@ bool _tryGetStringList(std::string_view url, std::vector& list) { std::string_view data = response.data; - auto lines = data.splitLines(); + auto lines = OpenShock::StringSplitNewLines(data); list.reserve(lines.size()); for (auto line : lines) { - line = line.trim(); + line = OpenShock::StringTrim(line); if (line.empty()) { continue; } - list.push_back(line.toString()); + list.push_back(std::string(line)); } return true; @@ -580,21 +582,21 @@ bool OtaUpdateManager::TryGetFirmwareRelease(const OpenShock::SemVer& version, F return false; } - auto hashesLines = std::string_view(sha256HashesResponse.data).splitLines(); + auto hashesLines = OpenShock::StringSplitNewLines(sha256HashesResponse.data); // Parse hashes. bool foundAppHash = false, foundFilesystemHash = false; for (std::string_view line : hashesLines) { - auto parts = line.splitWhitespace(); + auto parts = OpenShock::StringSplitWhiteSpace(line); if (parts.size() != 2) { ESP_LOGE(TAG, "Invalid hashes entry: %.*s", line.size(), line.data()); return false; } - auto hash = parts[0].trim(); - auto file = parts[1].trim(); + auto hash = OpenShock::StringTrim(parts[0]); + auto file = OpenShock::StringTrim(parts[1]); - if (file.startsWith("./"_sv)) { + if (OpenShock::StringStartsWith(file, "./"sv)) { file = file.substr(2); } diff --git a/src/SemVer.cpp b/src/SemVer.cpp index 162a90b8..048696a4 100644 --- a/src/SemVer.cpp +++ b/src/SemVer.cpp @@ -3,6 +3,7 @@ const char* const TAG = "SemVer"; #include "Logging.h" +#include "util/StringUtils.h" using namespace OpenShock; @@ -145,7 +146,7 @@ bool _semverIsVersionCore(std::string_view str) { return false; } - auto parts = str.split('.'); + auto parts = OpenShock::StringSplit(str, '.'); if (parts.size() != 3) { return false; } @@ -253,7 +254,7 @@ std::string SemVer::toString() const { } bool OpenShock::TryParseSemVer(std::string_view semverStr, SemVer& semver) { - auto parts = semverStr.split('.'); + auto parts = OpenShock::StringSplit(semverStr, '.'); if (parts.size() < 3) { ESP_LOGE(TAG, "Must have at least 3 parts: %.*s", semverStr.length(), semverStr.data()); return false; diff --git a/src/config/WiFiConfig.cpp b/src/config/WiFiConfig.cpp index d069b188..f0f8ec16 100644 --- a/src/config/WiFiConfig.cpp +++ b/src/config/WiFiConfig.cpp @@ -9,7 +9,7 @@ using namespace OpenShock::Config; WiFiConfig::WiFiConfig() : accessPointSSID(OPENSHOCK_FW_AP_PREFIX), hostname(OPENSHOCK_FW_HOSTNAME), credentialsList() { } -WiFiConfig::WiFiConfig(std::string_view accessPointSSID, std::string_view hostname, const std::vector& credentialsList) : accessPointSSID(accessPointSSID.toString()), hostname(hostname.toString()), credentialsList(credentialsList) { } +WiFiConfig::WiFiConfig(std::string_view accessPointSSID, std::string_view hostname, const std::vector& credentialsList) : accessPointSSID(std::string(accessPointSSID)), hostname(std::string(hostname)), credentialsList(credentialsList) { } void WiFiConfig::ToDefault() { accessPointSSID = OPENSHOCK_FW_AP_PREFIX; diff --git a/src/config/WiFiCredentials.cpp b/src/config/WiFiCredentials.cpp index f152fe8d..c6d9f4d1 100644 --- a/src/config/WiFiCredentials.cpp +++ b/src/config/WiFiCredentials.cpp @@ -10,7 +10,7 @@ using namespace OpenShock::Config; WiFiCredentials::WiFiCredentials() : id(0), ssid(), password() { } -WiFiCredentials::WiFiCredentials(uint8_t id, std::string_view ssid, std::string_view password) : id(id), ssid(ssid.toString()), password(password.toString()) { } +WiFiCredentials::WiFiCredentials(uint8_t id, std::string_view ssid, std::string_view password) : id(id), ssid(std::string(ssid)), password(std::string(password)) { } void WiFiCredentials::ToDefault() { id = 0; diff --git a/src/http/HTTPRequestManager.cpp b/src/http/HTTPRequestManager.cpp index c8906d75..2793d349 100644 --- a/src/http/HTTPRequestManager.cpp +++ b/src/http/HTTPRequestManager.cpp @@ -5,15 +5,19 @@ const char* const TAG = "HTTPRequestManager"; #include "Common.h" #include "Logging.h" #include "Time.h" +#include "util/StringUtils.h" #include #include #include #include +#include #include #include +using namespace std::string_view_literals; + const std::size_t HTTP_BUFFER_SIZE = 4096LLU; const int HTTP_DOWNLOAD_SIZE_LIMIT = 200 * 1024 * 1024; // 200 MB @@ -104,20 +108,35 @@ using namespace OpenShock; std::string_view _getDomain(std::string_view url) { if (url.empty()) { - return std::string_view::Null(); + return {}; + } + + // Remove the protocol eg. "https://api.example.com:443/path" -> "api.example.com:443/path" + auto seperator = url.find("://"); + if (seperator != std::string_view::npos) { + url.substr(seperator + 3); } - // Remove the protocol, port, and path eg. "https://api.example.com:443/path" -> "api.example.com" - url = url.afterDelimiter("://"_sv).beforeDelimiter('/').beforeDelimiter(':'); + // Remove the path eg. "api.example.com:443/path" -> "api.example.com:443" + seperator = url.find('/'); + if (seperator != std::string_view::npos) { + url = url.substr(0, seperator); + } + + // Remove the port eg. "api.example.com:443" -> "api.example.com" + seperator = url.rfind(':'); + if (seperator != std::string_view::npos) { + url = url.substr(0, seperator); + } // Remove all subdomains eg. "api.example.com" -> "example.com" - auto domainSep = url.rfind('.'); - if (domainSep == std::string_view::npos) { + seperator = url.rfind('.'); + if (seperator == std::string_view::npos) { return url; // E.g. "localhost" } - domainSep = url.rfind('.', domainSep - 1); - if (domainSep != std::string_view::npos) { - url = url.substr(domainSep + 1); + seperator = url.rfind('.', seperator - 1); + if (seperator != std::string_view::npos) { + url = url.substr(seperator + 1); } return url; @@ -140,7 +159,7 @@ std::shared_ptr _rateLimitFactory(std::string_view domain) { } std::shared_ptr _getRateLimiter(std::string_view url) { - auto domain = _getDomain(url).toString(); + auto domain = std::string(_getDomain(url)); if (domain.empty()) { return nullptr; } @@ -159,7 +178,7 @@ std::shared_ptr _getRateLimiter(std::string_view url) { } void _setupClient(HTTPClient& client) { - client.setUserAgent(OpenShock::Constants::FW_USERAGENT_sv.toArduinoString()); + client.setUserAgent(OpenShock::Constants::FW_USERAGENT); } struct StreamReaderResult { @@ -431,7 +450,7 @@ HTTP::Response _doGetStream( uint32_t timeoutMs ) { int64_t begin = OpenShock::millis(); - if (!client.begin(url.toArduinoString())) { + if (!client.begin(OpenShock::StringToArduinoString(url))) { ESP_LOGE(TAG, "Failed to begin HTTP request"); return {HTTP::RequestResult::RequestFailed, 0}; } diff --git a/src/http/JsonAPI.cpp b/src/http/JsonAPI.cpp index de77dde3..f5d4af18 100644 --- a/src/http/JsonAPI.cpp +++ b/src/http/JsonAPI.cpp @@ -2,6 +2,7 @@ #include "Common.h" #include "config/Config.h" +#include "util/StringUtils.h" using namespace OpenShock; @@ -37,7 +38,7 @@ HTTP::Response HTTP::JsonAPI::GetDev uri, { { "Accept", "application/json"}, - {"DeviceToken", deviceToken.toArduinoString()} + {"DeviceToken", OpenShock::StringToArduinoString(deviceToken)} }, Serialization::JsonAPI::ParseDeviceInfoJsonResponse, {200, 401} @@ -57,7 +58,7 @@ HTTP::Response HTTP::JsonAPI::AssignL uri, { { "Accept", "application/json"}, - {"DeviceToken", deviceToken.toArduinoString()} + {"DeviceToken", OpenShock::StringToArduinoString(deviceToken)} }, Serialization::JsonAPI::ParseAssignLcgJsonResponse, {200, 401} diff --git a/src/intconv.cpp b/src/intconv.cpp index b6856e56..caa64410 100644 --- a/src/intconv.cpp +++ b/src/intconv.cpp @@ -2,8 +2,11 @@ #include #include +#include #include +using namespace std::string_view_literals; + template constexpr unsigned int NumDigits() { static_assert(std::is_integral::value); @@ -136,189 +139,189 @@ static_assert(NumDigits() == 20, "NumDigits test for int64_t failed"); constexpr bool test_spanToUT8() { uint8_t u8 = 0; - return spanToUT("255"_sv, u8) && u8 == 255; + return spanToUT("255"sv, u8) && u8 == 255; } static_assert(test_spanToUT8(), "test_spanToUT8 failed"); constexpr bool test_spanToUT16() { uint16_t u16 = 0; - return spanToUT("65535"_sv, u16) && u16 == 65'535; + return spanToUT("65535"sv, u16) && u16 == 65'535; } static_assert(test_spanToUT16(), "test_spanToUT16 failed"); constexpr bool test_spanToUT32() { uint32_t u32 = 0; - return spanToUT("4294967295"_sv, u32) && u32 == 4'294'967'295U; + return spanToUT("4294967295"sv, u32) && u32 == 4'294'967'295U; } static_assert(test_spanToUT32(), "test_spanToUT32 failed"); constexpr bool test_spanToUT64() { uint64_t u64 = 0; - return spanToUT("18446744073709551615"_sv, u64) && u64 == 18'446'744'073'709'551'615ULL; + return spanToUT("18446744073709551615"sv, u64) && u64 == 18'446'744'073'709'551'615ULL; } static_assert(test_spanToUT64(), "test_spanToUT64 failed"); constexpr bool test_spanToUT8Overflow() { uint8_t u8 = 0; - return !spanToUT("256"_sv, u8); // Overflow + return !spanToUT("256"sv, u8); // Overflow } static_assert(test_spanToUT8Overflow(), "test_spanToUT8Overflow failed"); constexpr bool test_spanToUT16Overflow() { uint16_t u16 = 0; - return !spanToUT("70000"_sv, u16); // Overflow + return !spanToUT("70000"sv, u16); // Overflow } static_assert(test_spanToUT16Overflow(), "test_spanToUT16Overflow failed"); constexpr bool test_spanToUT32Overflow() { uint32_t u32 = 0; - return !spanToUT("4294967296"_sv, u32); // Overflow + return !spanToUT("4294967296"sv, u32); // Overflow } static_assert(test_spanToUT32Overflow(), "test_spanToUT32Overflow failed"); constexpr bool test_spanToUT64Overflow() { uint64_t u64 = 0; - return !spanToUT("18446744073709551616"_sv, u64); // Overflow + return !spanToUT("18446744073709551616"sv, u64); // Overflow } static_assert(test_spanToUT64Overflow(), "test_spanToUT64Overflow failed"); constexpr bool test_spanToST8() { int8_t i8 = 0; - return spanToST("-127"_sv, i8) && i8 == -127; + return spanToST("-127"sv, i8) && i8 == -127; } static_assert(test_spanToST8(), "test_spanToST8 failed"); constexpr bool test_spanToST16() { int16_t i16 = 0; - return spanToST("32767"_sv, i16) && i16 == 32'767; + return spanToST("32767"sv, i16) && i16 == 32'767; } static_assert(test_spanToST16(), "test_spanToST16 failed"); constexpr bool test_spanToST32() { int32_t i32 = 0; - return spanToST("-2147483647"_sv, i32) && i32 == -2'147'483'647; + return spanToST("-2147483647"sv, i32) && i32 == -2'147'483'647; } static_assert(test_spanToST32(), "test_spanToST32 failed"); constexpr bool test_spanToST64() { int64_t i64 = 0; - return spanToST("9223372036854775807"_sv, i64) && i64 == 9'223'372'036'854'775'807LL; + return spanToST("9223372036854775807"sv, i64) && i64 == 9'223'372'036'854'775'807LL; } static_assert(test_spanToST64(), "test_spanToST64 failed"); constexpr bool test_spanToST8Underflow() { int8_t i8 = 0; - return !spanToST("-128"_sv, i8); // Underflow + return !spanToST("-128"sv, i8); // Underflow } static_assert(test_spanToST8Underflow(), "test_spanToST8Underflow failed"); constexpr bool test_spanToST8Overflow() { int8_t i8 = 0; - return !spanToST("128"_sv, i8); // Overflow + return !spanToST("128"sv, i8); // Overflow } static_assert(test_spanToST8Overflow(), "test_spanToST8Overflow failed"); constexpr bool test_spanToST16Underflow() { int16_t i16 = 0; - return !spanToST("-32769"_sv, i16); // Underflow + return !spanToST("-32769"sv, i16); // Underflow } static_assert(test_spanToST16Underflow(), "test_spanToST16Underflow failed"); constexpr bool test_spanToST16Overflow() { int16_t i16 = 0; - return !spanToST("32768"_sv, i16); // Overflow + return !spanToST("32768"sv, i16); // Overflow } static_assert(test_spanToST16Overflow(), "test_spanToST16Overflow failed"); constexpr bool test_spanToST32Underflow() { int32_t i32 = 0; - return !spanToST("-2147483649"_sv, i32); // Underflow + return !spanToST("-2147483649"sv, i32); // Underflow } static_assert(test_spanToST32Underflow(), "test_spanToST32Underflow failed"); constexpr bool test_spanToST32Overflow() { int32_t i32 = 0; - return !spanToST("2147483648"_sv, i32); // Overflow + return !spanToST("2147483648"sv, i32); // Overflow } static_assert(test_spanToST32Overflow(), "test_spanToST32Overflow failed"); constexpr bool test_spanToST64Underflow() { int64_t i64 = 0; - return !spanToST("-9223372036854775809"_sv, i64); // Underflow + return !spanToST("-9223372036854775809"sv, i64); // Underflow } static_assert(test_spanToST64Underflow(), "test_spanToST64Underflow failed"); constexpr bool test_spanToST64Overflow() { int64_t i64 = 0; - return !spanToST("9223372036854775808"_sv, i64); // Overflow + return !spanToST("9223372036854775808"sv, i64); // Overflow } static_assert(test_spanToST64Overflow(), "test_spanToST64Overflow failed"); constexpr bool test_spanToSTEmptyString() { int8_t i8 = 0; - return !spanToST(""_sv, i8); // Empty string + return !spanToST(""sv, i8); // Empty string } static_assert(test_spanToSTEmptyString(), "test_spanToSTEmptyString failed"); constexpr bool test_spanToSTJustNegativeSign() { int16_t i16 = 0; - return !spanToST("-"_sv, i16); // Just a negative sign + return !spanToST("-"sv, i16); // Just a negative sign } static_assert(test_spanToSTJustNegativeSign(), "test_spanToSTJustNegativeSign failed"); constexpr bool test_spanToSTNegativeZero() { int32_t i32 = 0; - return !spanToST("-0"_sv, i32); // Negative zero + return !spanToST("-0"sv, i32); // Negative zero } static_assert(test_spanToSTNegativeZero(), "test_spanToSTNegativeZero failed"); constexpr bool test_spanToSTInvalidCharacter() { int32_t i32 = 0; - return !spanToST("+123"_sv, i32); // Invalid character + return !spanToST("+123"sv, i32); // Invalid character } static_assert(test_spanToSTInvalidCharacter(), "test_spanToSTInvalidCharacter failed"); constexpr bool test_spanToSTLeadingSpace() { int64_t i64 = 0; - return !spanToST(" 123"_sv, i64); // Leading space + return !spanToST(" 123"sv, i64); // Leading space } static_assert(test_spanToSTLeadingSpace(), "test_spanToSTLeadingSpace failed"); constexpr bool test_spanToSTTrailingSpace() { int64_t i64 = 0; - return !spanToST("123 "_sv, i64); // Trailing space + return !spanToST("123 "sv, i64); // Trailing space } static_assert(test_spanToSTTrailingSpace(), "test_spanToSTTrailingSpace failed"); constexpr bool test_spanToSTLeadingZero() { int64_t i64 = 0; - return !spanToST("0123"_sv, i64); // Leading zero + return !spanToST("0123"sv, i64); // Leading zero } static_assert(test_spanToSTLeadingZero(), "test_spanToSTLeadingZero failed"); diff --git a/src/serial/SerialInputHandler.cpp b/src/serial/SerialInputHandler.cpp index 9bbe01a2..22eed9a3 100644 --- a/src/serial/SerialInputHandler.cpp +++ b/src/serial/SerialInputHandler.cpp @@ -14,6 +14,7 @@ const char* const TAG = "SerialInputHandler"; #include "serialization/JsonSerial.h" #include "Time.h" #include "util/Base64Utils.h" +#include "util/StringUtils.h" #include "wifi/WiFiManager.h" #include @@ -23,6 +24,31 @@ const char* const TAG = "SerialInputHandler"; #include #include +namespace std { + struct hash_ci { + std::size_t operator()(std::string_view str) const { + std::size_t hash = 7; + + for (int i = 0; i < str.size(); ++i) { + hash = hash * 31 + tolower(str[i]); + } + + return hash; + } + }; + + template<> + struct less { + bool operator()(std::string_view a, std::string_view b) const { return a < b; } + }; + + struct equals_ci { + bool operator()(std::string_view a, std::string_view b) const { return strncasecmp(a.data(), b.data(), std::max(a.size(), b.size())) == 0; } + }; +} // namespace std + +using namespace std::string_view_literals; + #define SERPR_SYS(format, ...) Serial.printf("$SYS$|" format "\n", ##__VA_ARGS__) #define SERPR_RESPONSE(format, ...) SERPR_SYS("Response|" format, ##__VA_ARGS__) #define SERPR_SUCCESS(format, ...) SERPR_SYS("Success|" format, ##__VA_ARGS__) @@ -30,7 +56,7 @@ const char* const TAG = "SerialInputHandler"; using namespace OpenShock; -const int64_t PASTE_INTERVAL_THRESHOLD_MS = 20; +const int64_t PASTE_INTERVAL_THRESHOLD_MS = 20; const std::size_t SERIAL_BUFFER_CLEAR_THRESHOLD = 512; struct SerialCmdHandler { @@ -52,7 +78,7 @@ bool _tryParseBool(std::string_view str, bool& out) { return false; } - str = str.trim(); + str = OpenShock::StringTrim(str); if (str.length() > 5) { return false; @@ -170,15 +196,7 @@ void _handleDomainCommand(std::string_view arg) { return; } - ESP_LOGI( - TAG, - "Successfully connected to \"%.*s\", version: %s, commit: %s, current time: %s", - arg.length(), - arg.data(), - resp.data.version.c_str(), - resp.data.commit.c_str(), - resp.data.currentTime.c_str() - ); + ESP_LOGI(TAG, "Successfully connected to \"%.*s\", version: %s, commit: %s, current time: %s", arg.length(), arg.data(), resp.data.version.c_str(), resp.data.commit.c_str(), resp.data.currentTime.c_str()); bool result = OpenShock::Config::SetBackendDomain(arg); @@ -228,7 +246,7 @@ void _handleLcgOverrideCommand(std::string_view arg) { return; } - if (arg.startsWith("clear")) { + if (OpenShock::StringStartsWith(arg, "clear"sv)) { if (arg.size() != 5) { SERPR_ERROR("Invalid command (clear command should not have any arguments)"); return; @@ -243,7 +261,7 @@ void _handleLcgOverrideCommand(std::string_view arg) { return; } - if (arg.startsWith("set ")) { + if (OpenShock::StringStartsWith(arg, "set "sv)) { if (arg.size() <= 4) { SERPR_ERROR("Invalid command (set command should have an argument)"); return; @@ -338,8 +356,8 @@ void _handleNetworksCommand(std::string_view arg) { std::vector creds; - uint8_t id = 1; - cJSON* network = nullptr; + uint8_t id = 1; + cJSON* network = nullptr; cJSON_ArrayForEach(network, root) { Config::WiFiCredentials cred; @@ -558,7 +576,7 @@ void _handleRFTransmitCommand(std::string_view arg) { } void _handleHelpCommand(std::string_view arg) { - arg = arg.trim(); + arg = OpenShock::StringTrim(arg); if (arg.empty()) { SerialInputHandler::PrintWelcomeHeader(); @@ -603,7 +621,7 @@ factoryreset reset device to factory defaults and restart } static const SerialCmdHandler kVersionCmdHandler = { - "version"_sv, + "version"sv, R"(version Print version information Example: @@ -612,7 +630,7 @@ static const SerialCmdHandler kVersionCmdHandler = { _handleVersionCommand, }; static const SerialCmdHandler kRestartCmdHandler = { - "restart"_sv, + "restart"sv, R"(restart Restart the board Example: @@ -621,7 +639,7 @@ static const SerialCmdHandler kRestartCmdHandler = { _handleRestartCommand, }; static const SerialCmdHandler kSystemInfoCmdHandler = { - "sysinfo"_sv, + "sysinfo"sv, R"(sysinfo Get system information from RTOS, WiFi, etc. Example: @@ -630,7 +648,7 @@ static const SerialCmdHandler kSystemInfoCmdHandler = { _handleDebugInfoCommand, }; static const SerialCmdHandler kSerialEchoCmdHandler = { - "echo"_sv, + "echo"sv, R"(echo Get the serial echo status. If enabled, typed characters are echoed back to the serial port. @@ -645,7 +663,7 @@ echo [] _handleSerialEchoCommand, }; static const SerialCmdHandler kValidGpiosCmdHandler = { - "validgpios"_sv, + "validgpios"sv, R"(validgpios List all valid GPIO pins Example: @@ -654,7 +672,7 @@ static const SerialCmdHandler kValidGpiosCmdHandler = { _handleValidGpiosCommand, }; static const SerialCmdHandler kRfTxPinCmdHandler = { - "rftxpin"_sv, + "rftxpin"sv, R"(rftxpin Get the GPIO pin used for the radio transmitter. @@ -668,7 +686,7 @@ rftxpin [] _handleRfTxPinCommand, }; static const SerialCmdHandler kDomainCmdHandler = { - "domain"_sv, + "domain"sv, R"(domain Get the backend domain. @@ -682,7 +700,7 @@ domain [] _handleDomainCommand, }; static const SerialCmdHandler kAuthTokenCmdHandler = { - "authtoken"_sv, + "authtoken"sv, R"(authtoken Get the backend auth token. @@ -715,7 +733,7 @@ lcgoverride clear _handleLcgOverrideCommand, }; static const SerialCmdHandler kNetworksCmdHandler = { - "networks"_sv, + "networks"sv, R"(networks Get all saved networks. @@ -732,7 +750,7 @@ networks [] _handleNetworksCommand, }; static const SerialCmdHandler kKeepAliveCmdHandler = { - "keepalive"_sv, + "keepalive"sv, R"(keepalive Get the shocker keep-alive status. @@ -746,7 +764,7 @@ keepalive [] _handleKeepAliveCommand, }; static const SerialCmdHandler kJsonConfigCmdHandler = { - "jsonconfig"_sv, + "jsonconfig"sv, R"(jsonconfig Get the configuration as JSON Example: @@ -762,7 +780,7 @@ jsonconfig _handleJsonConfigCommand, }; static const SerialCmdHandler kRawConfigCmdHandler = { - "rawconfig"_sv, + "rawconfig"sv, R"(rawconfig Get the raw binary config Example: @@ -778,7 +796,7 @@ rawconfig _handleRawConfigCommand, }; static const SerialCmdHandler kRfTransmitCmdHandler = { - "rftransmit"_sv, + "rftransmit"sv, R"(rftransmit Transmit a RF command Arguments: @@ -794,7 +812,7 @@ static const SerialCmdHandler kRfTransmitCmdHandler = { _handleRFTransmitCommand, }; static const SerialCmdHandler kFactoryResetCmdHandler = { - "factoryreset"_sv, + "factoryreset"sv, R"(factoryreset Reset the device to factory defaults and restart Example: @@ -803,7 +821,7 @@ static const SerialCmdHandler kFactoryResetCmdHandler = { _handleFactoryResetCommand, }; static const SerialCmdHandler khelpCmdHandler = { - "help"_sv, + "help"sv, R"(help [] Print help information Arguments: @@ -853,13 +871,13 @@ int findLineStart(const char* buffer, int bufferSize, int lineEnd) { } void processSerialLine(std::string_view line) { - line = line.trim(); + line = OpenShock::StringTrim(line); if (line.empty()) { SERPR_ERROR("No command"); return; } - auto parts = line.split(' ', 1); + auto parts = OpenShock::StringSplit(line, ' ', 1); std::string_view command = parts[0]; std::string_view arguments = parts.size() > 1 ? parts[1] : std::string_view(); @@ -914,7 +932,7 @@ void SerialInputHandler::Update() { static char* buffer = nullptr; // TODO: Clean up this buffer every once in a while static std::size_t bufferSize = 0; static std::size_t bufferIndex = 0; - static int64_t lastEcho = 0; + static int64_t lastEcho = 0; static bool suppressingPaste = false; while (true) { @@ -980,7 +998,7 @@ void SerialInputHandler::Update() { break; } - std::string_view line = std::string_view(buffer, lineEnd).trim(); + std::string_view line = OpenShock::StringTrim(std::string_view(buffer, lineEnd)); Serial.printf("\r> %.*s\n", line.size(), line.data()); diff --git a/src/wifi/WiFiManager.cpp b/src/wifi/WiFiManager.cpp index 1d217a33..ce401b4c 100644 --- a/src/wifi/WiFiManager.cpp +++ b/src/wifi/WiFiManager.cpp @@ -180,7 +180,7 @@ bool _authenticate(const WiFiNetwork& net, std::string_view password) { Serialization::Local::SerializeWiFiNetworkEvent(Serialization::Types::WifiNetworkEventType::Saved, net, CaptivePortal::BroadcastMessageBIN); - return _connect(net.ssid, password.toString()); + return _connect(net.ssid, std::string(password)); } void _evWiFiConnected(arduino_event_t* event) { From 8d0b6a0e79faa9ff05eaabc45e77b11d14d3b69b Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 6 Sep 2024 11:46:52 +0200 Subject: [PATCH 3/6] Some extra fixes --- include/util/IPAddressUtils.h | 4 ++-- src/config/internal/utils.cpp | 4 ++-- src/util/IPAddressUtils.cpp | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/util/IPAddressUtils.h b/include/util/IPAddressUtils.h index ee5eadae..d9cfe9c9 100644 --- a/include/util/IPAddressUtils.h +++ b/include/util/IPAddressUtils.h @@ -2,8 +2,8 @@ #include -#include "StringView.h" +#include namespace OpenShock { - bool IPV4AddressFromStringView(IPAddress& ip, StringView sv); + bool IPV4AddressFromStringView(IPAddress& ip, std::string_view sv); } diff --git a/src/config/internal/utils.cpp b/src/config/internal/utils.cpp index 69d3f916..bfde56e2 100644 --- a/src/config/internal/utils.cpp +++ b/src/config/internal/utils.cpp @@ -53,7 +53,7 @@ bool Config::Internal::Utils::FromFbsIPAddress(IPAddress& ip, const flatbuffers: return false; } - StringView view(*fbsIP); + std::string_view view(*fbsIP); if (!OpenShock::IPV4AddressFromStringView(ip, view)) { OS_LOGE(TAG, "failed to parse IP address"); @@ -121,7 +121,7 @@ bool Config::Internal::Utils::FromJsonIPAddress(IPAddress& ip, const cJSON* json return false; } - StringView view(jsonVal->valuestring); + std::string_view view(jsonVal->valuestring); if (!OpenShock::IPV4AddressFromStringView(ip, view)) { OS_LOGE(TAG, "failed to parse IP address at '%s'", name); diff --git a/src/util/IPAddressUtils.cpp b/src/util/IPAddressUtils.cpp index a6dbc5c3..5fbe14a9 100644 --- a/src/util/IPAddressUtils.cpp +++ b/src/util/IPAddressUtils.cpp @@ -1,15 +1,16 @@ #include "util/IPAddressUtils.h" #include "intconv.h" +#include "util/StringUtils.h" const char* const TAG = "Util::IPAddressUtils"; -bool OpenShock::IPV4AddressFromStringView(IPAddress& ip, StringView sv) { - if (sv.isNullOrEmpty()) { +bool OpenShock::IPV4AddressFromStringView(IPAddress& ip, std::string_view sv) { + if (sv.empty()) { return false; } - auto parts = sv.split('.'); + auto parts = OpenShock::StringSplit(sv, '.'); if (parts.size() != 4) { return false; // Must have 4 octets } From 7f5d021885c84485d626fcd409540229ad0e1431 Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 6 Sep 2024 11:57:57 +0200 Subject: [PATCH 4/6] Move non-constexpr functions out of header --- include/util/StringUtils.h | 69 +++----------------------------------- src/util/StringUtils.cpp | 69 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 64 deletions(-) diff --git a/include/util/StringUtils.h b/include/util/StringUtils.h index 1f6db043..ee4d07ba 100644 --- a/include/util/StringUtils.h +++ b/include/util/StringUtils.h @@ -11,67 +11,6 @@ namespace OpenShock { bool FormatToString(std::string& out, const char* format, ...); - inline std::vector StringSplit(const std::string_view view, char delimiter, std::size_t maxSplits = std::numeric_limits::max()) { - if (view.empty()) { - return {}; - } - - std::vector result = {}; - - std::size_t pos = 0; - std::size_t splits = 0; - while (pos < view.size() && splits < maxSplits) { - std::size_t nextPos = view.find(delimiter, pos); - if (nextPos == std::string_view::npos) { - nextPos = view.size(); - } - - result.push_back(view.substr(pos, nextPos - pos)); - pos = nextPos + 1; - ++splits; - } - - if (pos < view.size()) { - result.push_back(view.substr(pos)); - } - - return result; - } - inline std::vector StringSplit(const std::string_view view, bool (*predicate)(char delimiter), std::size_t maxSplits = std::numeric_limits::max()) { - if (view.empty()) { - return {}; - } - - std::vector result = {}; - - const char* start = nullptr; - for (const char* ptr = view.begin(); ptr < view.end(); ++ptr) { - if (predicate(*ptr)) { - if (start != nullptr) { - result.emplace_back(std::string_view(start, ptr - start)); - start = nullptr; - } - } else if (start == nullptr) { - start = ptr; - } - } - - if (start != nullptr) { - result.emplace_back(std::string_view(start, view.end() - start)); - } - - return result; - } - inline std::vector StringSplitNewLines(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()) { - return StringSplit( - view, [](char c) { return c == '\r' || c == '\n'; }, maxSplits - ); - } - inline std::vector StringSplitWhiteSpace(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()) { - return StringSplit( - view, [](char c) { return isspace(c) != 0; }, maxSplits - ); - } constexpr std::string_view StringTrimLeft(std::string_view view) { if (view.empty()) { return view; @@ -102,7 +41,9 @@ namespace OpenShock { constexpr bool StringStartsWith(std::string_view view, std::string_view prefix) { return view.size() >= prefix.size() && view.substr(0, prefix.size()) == prefix; } - inline String StringToArduinoString(std::string_view view) { - return String(view.data(), view.size()); - } + std::vector StringSplit(const std::string_view view, char delimiter, std::size_t maxSplits = std::numeric_limits::max()); + std::vector StringSplit(const std::string_view view, bool (*predicate)(char delimiter), std::size_t maxSplits = std::numeric_limits::max()); + std::vector StringSplitNewLines(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()); + std::vector StringSplitWhiteSpace(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()); + String StringToArduinoString(std::string_view view); } // namespace OpenShock diff --git a/src/util/StringUtils.cpp b/src/util/StringUtils.cpp index 6e331c06..80e74146 100644 --- a/src/util/StringUtils.cpp +++ b/src/util/StringUtils.cpp @@ -57,3 +57,72 @@ bool OpenShock::FormatToString(std::string& out, const char* format, ...) { return true; } + +std::vector OpenShock::StringSplit(const std::string_view view, char delimiter, std::size_t maxSplits) { + if (view.empty()) { + return {}; + } + + std::vector result = {}; + + std::size_t pos = 0; + std::size_t splits = 0; + while (pos < view.size() && splits < maxSplits) { + std::size_t nextPos = view.find(delimiter, pos); + if (nextPos == std::string_view::npos) { + nextPos = view.size(); + } + + result.push_back(view.substr(pos, nextPos - pos)); + pos = nextPos + 1; + ++splits; + } + + if (pos < view.size()) { + result.push_back(view.substr(pos)); + } + + return result; +} + +std::vector OpenShock::StringSplit(const std::string_view view, bool (*predicate)(char delimiter), std::size_t maxSplits) { + if (view.empty()) { + return {}; + } + + std::vector result = {}; + + const char* start = nullptr; + for (const char* ptr = view.begin(); ptr < view.end(); ++ptr) { + if (predicate(*ptr)) { + if (start != nullptr) { + result.emplace_back(std::string_view(start, ptr - start)); + start = nullptr; + } + } else if (start == nullptr) { + start = ptr; + } + } + + if (start != nullptr) { + result.emplace_back(std::string_view(start, view.end() - start)); + } + + return result; +} + +std::vector OpenShock::StringSplitNewLines(const std::string_view view, std::size_t maxSplits) { + return StringSplit( + view, [](char c) { return c == '\r' || c == '\n'; }, maxSplits + ); +} + +std::vector OpenShock::StringSplitWhiteSpace(const std::string_view view, std::size_t maxSplits) { + return StringSplit( + view, [](char c) { return isspace(c) != 0; }, maxSplits + ); +} + +String OpenShock::StringToArduinoString(std::string_view view) { + return String(view.data(), view.size()); +} From 1218df1a45d8878af1e7d0c9dcbd90ff7bb876fc Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 6 Sep 2024 13:30:28 +0200 Subject: [PATCH 5/6] Better string split for fixed lengths --- include/util/StringUtils.h | 17 +++++++++++++++++ src/SemVer.cpp | 10 +++++----- src/util/IPAddressUtils.cpp | 4 ++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/util/StringUtils.h b/include/util/StringUtils.h index ee4d07ba..2b0bd786 100644 --- a/include/util/StringUtils.h +++ b/include/util/StringUtils.h @@ -41,6 +41,23 @@ namespace OpenShock { constexpr bool StringStartsWith(std::string_view view, std::string_view prefix) { return view.size() >= prefix.size() && view.substr(0, prefix.size()) == prefix; } + template + constexpr bool TryStringSplit(const std::string_view view, char delimiter, std::string_view (&out)[N]) { + std::size_t pos = 0; + std::size_t idx = 0; + while (pos < view.size() && idx < N) { + std::size_t nextPos = view.find(delimiter, pos); + if (nextPos == std::string_view::npos) { + nextPos = view.size(); + } + + out[idx] = view.substr(pos, nextPos - pos); + pos = nextPos + 1; + ++idx; + } + + return idx == N; + } std::vector StringSplit(const std::string_view view, char delimiter, std::size_t maxSplits = std::numeric_limits::max()); std::vector StringSplit(const std::string_view view, bool (*predicate)(char delimiter), std::size_t maxSplits = std::numeric_limits::max()); std::vector StringSplitNewLines(const std::string_view view, std::size_t maxSplits = std::numeric_limits::max()); diff --git a/src/SemVer.cpp b/src/SemVer.cpp index 22605f8e..4d9d544d 100644 --- a/src/SemVer.cpp +++ b/src/SemVer.cpp @@ -146,8 +146,8 @@ bool _semverIsVersionCore(std::string_view str) { return false; } - auto parts = OpenShock::StringSplit(str, '.'); - if (parts.size() != 3) { + std::string_view parts[3]; + if (!OpenShock::TryStringSplit(str, '.', parts)) { return false; } @@ -254,9 +254,9 @@ std::string SemVer::toString() const { } bool OpenShock::TryParseSemVer(std::string_view semverStr, SemVer& semver) { - auto parts = OpenShock::StringSplit(semverStr, '.'); - if (parts.size() < 3) { - OS_LOGE(TAG, "Must have at least 3 parts: %.*s", semverStr.length(), semverStr.data()); + std::string_view parts[3]; + if (!OpenShock::TryStringSplit(semverStr, '.', parts)) { + OS_LOGE(TAG, "Failed to split version string: %.*s", semverStr.length(), semverStr.data()); return false; } diff --git a/src/util/IPAddressUtils.cpp b/src/util/IPAddressUtils.cpp index 5fbe14a9..61023d37 100644 --- a/src/util/IPAddressUtils.cpp +++ b/src/util/IPAddressUtils.cpp @@ -10,8 +10,8 @@ bool OpenShock::IPV4AddressFromStringView(IPAddress& ip, std::string_view sv) { return false; } - auto parts = OpenShock::StringSplit(sv, '.'); - if (parts.size() != 4) { + std::string_view parts[4]; + if (!OpenShock::TryStringSplit(sv, '.', parts)) { return false; // Must have 4 octets } From 90ab129f3c2a790982e58dc21fb4b97e4c9fa696 Mon Sep 17 00:00:00 2001 From: hhvrc Date: Fri, 6 Sep 2024 13:30:41 +0200 Subject: [PATCH 6/6] Fix const qualifier --- include/util/StringUtils.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/util/StringUtils.h b/include/util/StringUtils.h index 2b0bd786..08feb6e5 100644 --- a/include/util/StringUtils.h +++ b/include/util/StringUtils.h @@ -11,7 +11,7 @@ namespace OpenShock { bool FormatToString(std::string& out, const char* format, ...); - constexpr std::string_view StringTrimLeft(std::string_view view) { + constexpr std::string_view StringTrimLeft(const std::string_view view) { if (view.empty()) { return view; } @@ -23,7 +23,7 @@ namespace OpenShock { return view.substr(pos); } - constexpr std::string_view StringTrimRight(std::string_view view) { + constexpr std::string_view StringTrimRight(const std::string_view view) { if (view.empty()) { return view; } @@ -35,10 +35,10 @@ namespace OpenShock { return view.substr(0, pos + 1); } - constexpr std::string_view StringTrim(std::string_view view) { + constexpr std::string_view StringTrim(const std::string_view view) { return StringTrimLeft(StringTrimRight(view)); } - constexpr bool StringStartsWith(std::string_view view, std::string_view prefix) { + constexpr bool StringStartsWith(const std::string_view view, std::string_view prefix) { return view.size() >= prefix.size() && view.substr(0, prefix.size()) == prefix; } template