diff options
| author | Dan Engelbrecht <[email protected]> | 2024-10-03 12:35:44 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2024-10-03 12:35:44 +0200 |
| commit | db531191789f48a141c42fef229bca7a7922443d (patch) | |
| tree | cc1570bf8dedccb975d594bd91284ac5d0bd0bae /src | |
| parent | simplified CleanDirectory implementation (#182) (diff) | |
| download | zen-db531191789f48a141c42fef229bca7a7922443d.tar.xz zen-db531191789f48a141c42fef229bca7a7922443d.zip | |
cache get command (#183)
* move TryParseObjectId and TryParseIoHash to Oid::TryParse and IoHash::TryParse respectively
* zen cache-get command
Diffstat (limited to 'src')
| -rw-r--r-- | src/zen/cmds/cache_cmd.cpp | 130 | ||||
| -rw-r--r-- | src/zen/cmds/cache_cmd.h | 23 | ||||
| -rw-r--r-- | src/zen/zen.cpp | 2 | ||||
| -rw-r--r-- | src/zencore/compactbinaryjson.cpp | 42 | ||||
| -rw-r--r-- | src/zencore/include/zencore/iohash.h | 1 | ||||
| -rw-r--r-- | src/zencore/include/zencore/uid.h | 1 | ||||
| -rw-r--r-- | src/zencore/iohash.cpp | 18 | ||||
| -rw-r--r-- | src/zencore/uid.cpp | 28 |
8 files changed, 200 insertions, 45 deletions
diff --git a/src/zen/cmds/cache_cmd.cpp b/src/zen/cmds/cache_cmd.cpp index eecc3494e..d6fec3b12 100644 --- a/src/zen/cmds/cache_cmd.cpp +++ b/src/zen/cmds/cache_cmd.cpp @@ -5,6 +5,7 @@ #include <zencore/compress.h> #include <zencore/except.h> #include <zencore/filesystem.h> +#include <zencore/fmtutils.h> #include <zencore/logging.h> #include <zencore/scopeguard.h> #include <zencore/thread.h> @@ -514,4 +515,133 @@ CacheGenerateCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a return 0; } +CacheGetCommand::CacheGetCommand() +{ + m_Options.add_options()("h,help", "Print help"); + m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), "<hosturl>"); + m_Options + .add_option("", "n", "namespace", "Namespace to generate cache values/records for", cxxopts::value(m_Namespace), "<namespace>"); + m_Options.add_option("", "b", "bucket", "Bucket name to generate cache values/records for", cxxopts::value(m_Bucket), "<bucket>"); + m_Options.add_option("", "v", "valuekey", "Cache entry iohash id", cxxopts::value(m_ValueKey), "<valuekey>"); + m_Options.add_option("", + "a", + "attachmentid", + "For a cache entry record, get a particular attachment based on IoHash", + cxxopts::value(m_AttachmentId), + "<attachmentid>"); + m_Options.add_option("", "o", "output-path", "File path for output data", cxxopts::value(m_OutputPath), "<path>"); + m_Options.add_option("", "t", "text", "Ouput content of cache entry record as text", cxxopts::value(m_AsText), "<text>"); + m_Options.parse_positional({"namespace", "bucket", "valuekey", "attachmentid"}); + m_Options.positional_help("namespace bucket valuekey attachmentid"); +} + +CacheGetCommand::~CacheGetCommand() = default; + +int +CacheGetCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) +{ + ZEN_UNUSED(GlobalOptions); + + using namespace std::literals; + + if (!ParseOptions(argc, argv)) + { + return 0; + } + + m_HostName = ResolveTargetHostSpec(m_HostName); + + if (m_HostName.empty()) + { + throw zen::OptionParseException("unable to resolve server specification"); + } + + if (m_Namespace.empty()) + { + throw zen::OptionParseException("cache-get command requires a namespace"); + } + + if (m_Bucket.empty()) + { + throw zen::OptionParseException("cache-get command requires a bucket"); + } + + if (m_ValueKey.empty()) + { + throw zen::OptionParseException("cache-get command requires a value key"); + } + + IoHash ValueId; + if (!IoHash::TryParse(m_ValueKey, ValueId)) + { + throw zen::OptionParseException("cache-get --valuekey option requires a valid IoHash string"); + } + + IoHash AttachmentHash; + if (!m_AttachmentId.empty()) + { + if (!IoHash::TryParse(m_AttachmentId, AttachmentHash)) + { + throw zen::OptionParseException("cache-get --attachmentid option requires a valid IoHash string"); + } + } + + HttpClient Http(m_HostName); + + std::filesystem::path TargetPath; + if (!m_OutputPath.empty()) + { + TargetPath = std::filesystem::path(m_OutputPath); + if (std::filesystem::is_directory(TargetPath)) + { + TargetPath = TargetPath / (m_AttachmentId.empty() ? m_ValueKey : m_AttachmentId); + } + else + { + CreateDirectories(TargetPath.parent_path()); + } + } + if (TargetPath.empty()) + { + TargetPath = (m_AttachmentId.empty() ? m_ValueKey : m_AttachmentId); + } + + std::string Url = fmt::format("/z$/{}/{}/{}", m_Namespace, m_Bucket, m_ValueKey); + if (AttachmentHash != IoHash::Zero) + { + Url = fmt::format("{}/{}", Url, AttachmentHash); + } + if (HttpClient::Response Result = Http.Download(Url, std::filesystem::temp_directory_path()); Result) + { + IoBuffer ChunkData = Result.ResponsePayload; + if (m_AsText) + { + std::string StringData = Result.ToText(); + if (m_OutputPath.empty()) + { + ZEN_CONSOLE("{}", StringData); + } + else + { + WriteFile(TargetPath, IoBuffer(IoBuffer::Wrap, StringData.data(), StringData.length())); + ZEN_CONSOLE("Wrote {} to '{}' ({})", NiceBytes(StringData.length()), TargetPath, ToString(ChunkData.GetContentType())); + } + } + else + { + if (!MoveToFile(TargetPath, ChunkData)) + { + WriteFile(TargetPath, ChunkData); + } + ZEN_CONSOLE("Wrote {} to '{}' ({})", NiceBytes(ChunkData.GetSize()), TargetPath, ToString(ChunkData.GetContentType())); + } + } + else + { + Result.ThrowError("Failed to fetch data"sv); + } + + return 0; +} + } // namespace zen diff --git a/src/zen/cmds/cache_cmd.h b/src/zen/cmds/cache_cmd.h index b8181d5a2..c3184140a 100644 --- a/src/zen/cmds/cache_cmd.h +++ b/src/zen/cmds/cache_cmd.h @@ -93,4 +93,27 @@ private: uint32_t m_MaxAttachmentCount = 0; }; +class CacheGetCommand : public CacheStoreCommand +{ +public: + static constexpr char Name[] = "cache-get"; + static constexpr char Description[] = "Get cache values/records or attachments from a bucket"; + + CacheGetCommand(); + ~CacheGetCommand(); + + virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override; + virtual cxxopts::Options& Options() override { return m_Options; } + +private: + cxxopts::Options m_Options{Name, Description}; + std::string m_HostName; + std::string m_Namespace; + std::string m_Bucket; + std::string m_ValueKey; + std::string m_AttachmentId; + std::string m_OutputPath; + bool m_AsText = false; +}; + } // namespace zen diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp index 79338f6f3..026e8c84f 100644 --- a/src/zen/zen.cpp +++ b/src/zen/zen.cpp @@ -290,6 +290,7 @@ main(int argc, char** argv) AttachCommand AttachCmd; BenchCommand BenchCmd; CacheDetailsCommand CacheDetailsCmd; + CacheGetCommand CacheGetCmd; CacheGenerateCommand CacheGenerateCmd; CacheInfoCommand CacheInfoCmd; CacheStatsCommand CacheStatsCmd; @@ -344,6 +345,7 @@ main(int argc, char** argv) {"bench", &BenchCmd, "Utility command for benchmarking"}, {"cache-details", &CacheDetailsCmd, "Details on cache"}, {"cache-info", &CacheInfoCmd, "Info on cache, namespace or bucket"}, + {CacheGetCommand::Name, &CacheGetCmd, CacheGetCommand::Description}, {CacheGenerateCommand::Name, &CacheGenerateCmd, CacheGenerateCommand::Description}, {"cache-stats", &CacheStatsCmd, "Stats on cache"}, {"copy", &CopyCmd, "Copy file(s)"}, diff --git a/src/zencore/compactbinaryjson.cpp b/src/zencore/compactbinaryjson.cpp index 58a91c731..d8c8a8584 100644 --- a/src/zencore/compactbinaryjson.cpp +++ b/src/zencore/compactbinaryjson.cpp @@ -466,7 +466,7 @@ private: case Json::Type::STRING: { Oid Id; - if (TryParseObjectId(Json.string_value(), Id)) + if (Oid::TryParse(Json.string_value(), Id)) { if (FieldName.empty()) { @@ -481,7 +481,7 @@ private: } IoHash Hash; - if (TryParseIoHash(Json.string_value(), Hash)) + if (IoHash::TryParse(Json.string_value(), Hash)) { if (FieldName.empty()) { @@ -511,44 +511,6 @@ private: return true; } - - static constexpr AsciiSet HexCharSet = AsciiSet("0123456789abcdefABCDEF"); - - static bool TryParseObjectId(std::string_view Str, Oid& Id) - { - using namespace std::literals; - - if (Str.size() == Oid::StringLength && AsciiSet::HasOnly(Str, HexCharSet)) - { - Id = Oid::FromHexString(Str); - return true; - } - - if (Str.starts_with("0x"sv)) - { - return TryParseObjectId(Str.substr(2), Id); - } - - return false; - } - - static bool TryParseIoHash(std::string_view Str, IoHash& Hash) - { - using namespace std::literals; - - if (Str.size() == IoHash::StringLength && AsciiSet::HasOnly(Str, HexCharSet)) - { - Hash = IoHash::FromHexString(Str); - return true; - } - - if (Str.starts_with("0x"sv)) - { - return TryParseIoHash(Str.substr(2), Hash); - } - - return false; - } }; CbFieldIterator diff --git a/src/zencore/include/zencore/iohash.h b/src/zencore/include/zencore/iohash.h index a8fc9e6c1..9c9f487bb 100644 --- a/src/zencore/include/zencore/iohash.h +++ b/src/zencore/include/zencore/iohash.h @@ -50,6 +50,7 @@ struct IoHash static IoHash HashBuffer(const IoBuffer& Buffer); static IoHash FromHexString(const char* string); static IoHash FromHexString(const std::string_view string); + static bool TryParse(std::string_view Str, IoHash& Hash); const char* ToHexString(char* outString /* 40 characters + NUL terminator */) const; StringBuilderBase& ToHexString(StringBuilderBase& outBuilder) const; std::string ToHexString() const; diff --git a/src/zencore/include/zencore/uid.h b/src/zencore/include/zencore/uid.h index 08a335392..1b6fc3f6a 100644 --- a/src/zencore/include/zencore/uid.h +++ b/src/zencore/include/zencore/uid.h @@ -63,6 +63,7 @@ struct Oid const Oid& Generate(); [[nodiscard]] static Oid FromHexString(const std::string_view String); [[nodiscard]] static Oid TryFromHexString(const std::string_view String, const Oid& Default = Oid::Zero); + static bool TryParse(std::string_view Str, Oid& Id); StringBuilderBase& ToString(StringBuilderBase& OutString) const; void ToString(char OutString[StringLength]) const; std::string ToString() const; diff --git a/src/zencore/iohash.cpp b/src/zencore/iohash.cpp index 8f3f8da26..7200e6e3f 100644 --- a/src/zencore/iohash.cpp +++ b/src/zencore/iohash.cpp @@ -99,6 +99,24 @@ IoHash::FromHexString(std::string_view string) return io; } +bool +IoHash::TryParse(std::string_view Str, IoHash& Hash) +{ + using namespace std::literals; + + if (Str.size() == IoHash::StringLength) + { + return ParseHexBytes(Str.data(), Str.size(), Hash.Hash); + } + + if (Str.starts_with("0x"sv)) + { + return TryParse(Str.substr(2), Hash); + } + + return false; +} + const char* IoHash::ToHexString(char* outString /* 40 characters + NUL terminator */) const { diff --git a/src/zencore/uid.cpp b/src/zencore/uid.cpp index 8ef660c7a..d7636f2ad 100644 --- a/src/zencore/uid.cpp +++ b/src/zencore/uid.cpp @@ -102,12 +102,22 @@ Oid::TryFromHexString(const std::string_view String, const Oid& Default) } } -Oid -Oid::FromMemory(const void* Ptr) +bool +Oid::TryParse(std::string_view Str, Oid& Id) { - Oid Id; - memcpy(Id.OidBits, Ptr, sizeof Id); - return Id; + using namespace std::literals; + + if (Str.size() == Oid::StringLength) + { + return ParseHexBytes(Str.data(), Str.size(), reinterpret_cast<uint8_t*>(Id.OidBits)); + } + + if (Str.starts_with("0x"sv)) + { + return TryParse(Str.substr(2), Id); + } + + return false; } void @@ -136,6 +146,14 @@ Oid::ToString(StringBuilderBase& OutString) const return OutString; } +Oid +Oid::FromMemory(const void* Ptr) +{ + Oid Id; + memcpy(Id.OidBits, Ptr, sizeof Id); + return Id; +} + #if ZEN_WITH_TESTS TEST_CASE("Oid") |