aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2024-10-03 12:35:44 +0200
committerGitHub Enterprise <[email protected]>2024-10-03 12:35:44 +0200
commitdb531191789f48a141c42fef229bca7a7922443d (patch)
treecc1570bf8dedccb975d594bd91284ac5d0bd0bae /src
parentsimplified CleanDirectory implementation (#182) (diff)
downloadzen-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.cpp130
-rw-r--r--src/zen/cmds/cache_cmd.h23
-rw-r--r--src/zen/zen.cpp2
-rw-r--r--src/zencore/compactbinaryjson.cpp42
-rw-r--r--src/zencore/include/zencore/iohash.h1
-rw-r--r--src/zencore/include/zencore/uid.h1
-rw-r--r--src/zencore/iohash.cpp18
-rw-r--r--src/zencore/uid.cpp28
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")