add example handler
This adds an example handler to demonstrate how one can add a specific
type of BLOB handler.
Change-Id: Ib5421f1b945b45998b40d3939a4dab9cdf39aaa9
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/example/example.cpp b/example/example.cpp
new file mode 100644
index 0000000..de05f00
--- /dev/null
+++ b/example/example.cpp
@@ -0,0 +1,167 @@
+#include "example/example.hpp"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace blobs
+{
+
+constexpr char ExampleBlobHandler::supportedPath[];
+
+ExampleBlob* ExampleBlobHandler::getSession(uint16_t id)
+{
+ auto search = sessions.find(id);
+ if (search == sessions.end())
+ {
+ return nullptr;
+ }
+ /* Not thread-safe, however, the blob handler deliberately assumes serial
+ * execution. */
+ return &search->second;
+}
+
+bool ExampleBlobHandler::canHandleBlob(const std::string& path)
+{
+ return (path == supportedPath);
+}
+
+std::vector<std::string> ExampleBlobHandler::getBlobIds()
+{
+ return {supportedPath};
+}
+
+bool ExampleBlobHandler::deleteBlob(const std::string& path)
+{
+ return false;
+}
+
+bool ExampleBlobHandler::stat(const std::string& path, struct BlobMeta* meta)
+{
+ return false;
+}
+
+bool ExampleBlobHandler::open(uint16_t session, uint16_t flags,
+ const std::string& path)
+{
+ if (!canHandleBlob(path))
+ {
+ return false;
+ }
+
+ auto findSess = sessions.find(session);
+ if (findSess != sessions.end())
+ {
+ /* This session is already active. */
+ return false;
+ }
+ sessions[session] = ExampleBlob(session, flags);
+ return true;
+}
+
+std::vector<uint8_t> ExampleBlobHandler::read(uint16_t session, uint32_t offset,
+ uint32_t requestedSize)
+{
+ ExampleBlob* sess = getSession(session);
+ if (!sess)
+ {
+ return std::vector<uint8_t>();
+ }
+
+ /* Is the offset beyond the array? */
+ if (offset >= sizeof(sess->buffer))
+ {
+ return std::vector<uint8_t>();
+ }
+
+ /* Determine how many bytes we can read from the offset.
+ * In this case, if they read beyond "size" we allow it.
+ */
+ uint32_t remain = sizeof(sess->buffer) - offset;
+ uint32_t numBytes = std::min(remain, requestedSize);
+ /* Copy the bytes! */
+ std::vector<uint8_t> result(numBytes);
+ std::memcpy(result.data(), &sess->buffer[offset], numBytes);
+ return result;
+}
+
+bool ExampleBlobHandler::write(uint16_t session, uint32_t offset,
+ const std::vector<uint8_t>& data)
+{
+ ExampleBlob* sess = getSession(session);
+ if (!sess)
+ {
+ return false;
+ }
+ /* Is the offset beyond the array? */
+ if (offset >= sizeof(sess->buffer))
+ {
+ return false;
+ }
+ /* Determine whether all their bytes will fit. */
+ uint32_t remain = sizeof(sess->buffer) - offset;
+ if (data.size() > remain)
+ {
+ return false;
+ }
+ sess->length =
+ std::max(offset + data.size(),
+ static_cast<std::vector<uint8_t>::size_type>(sess->length));
+ std::memcpy(&sess->buffer[offset], data.data(), data.size());
+ return true;
+}
+
+bool ExampleBlobHandler::commit(uint16_t session,
+ const std::vector<uint8_t>& data)
+{
+ ExampleBlob* sess = getSession(session);
+ if (!sess)
+ {
+ return false;
+ }
+
+ /* Do something with the staged data!. */
+
+ return false;
+}
+
+bool ExampleBlobHandler::close(uint16_t session)
+{
+ ExampleBlob* sess = getSession(session);
+ if (!sess)
+ {
+ return false;
+ }
+
+ sessions.erase(session);
+ return true;
+}
+
+bool ExampleBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
+{
+ ExampleBlob* sess = getSession(session);
+ if (!sess)
+ {
+ return false;
+ }
+ if (!meta)
+ {
+ return false;
+ }
+ meta->size = sess->length;
+ meta->blobState = sess->state;
+ return true;
+}
+
+bool ExampleBlobHandler::expire(uint16_t session)
+{
+ ExampleBlob* sess = getSession(session);
+ if (!sess)
+ {
+ return false;
+ }
+ /* TODO: implement session expiration behavior. */
+ return false;
+}
+
+} // namespace blobs
diff --git a/example/example.hpp b/example/example.hpp
new file mode 100644
index 0000000..0ea9572
--- /dev/null
+++ b/example/example.hpp
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "blobs.hpp"
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace blobs
+{
+
+constexpr int kBufferSize = 1024;
+
+struct ExampleBlob
+{
+ ExampleBlob() = default;
+ ExampleBlob(uint16_t id, uint16_t flags) :
+ sessionId(id), flags(flags), length(0)
+ {
+ }
+
+ /* The blob handler session id. */
+ uint16_t sessionId;
+
+ /* The flags passed into open. */
+ uint16_t flags;
+
+ /* The buffer is a fixed size, but length represents the number of bytes
+ * expected to be used contiguously from offset 0.
+ */
+ uint32_t length;
+
+ /* The staging buffer. */
+ uint8_t buffer[kBufferSize];
+};
+
+class ExampleBlobHandler : public GenericBlobInterface
+{
+ public:
+ /* We want everything explicitly default. */
+ ExampleBlobHandler() = default;
+ ~ExampleBlobHandler() = default;
+ ExampleBlobHandler(const ExampleBlobHandler&) = default;
+ ExampleBlobHandler& operator=(const ExampleBlobHandler&) = default;
+ ExampleBlobHandler(ExampleBlobHandler&&) = default;
+ ExampleBlobHandler& operator=(ExampleBlobHandler&&) = default;
+
+ bool canHandleBlob(const std::string& path) override;
+ std::vector<std::string> getBlobIds() override;
+ bool deleteBlob(const std::string& path) override;
+ bool stat(const std::string& path, struct BlobMeta* meta) override;
+ bool open(uint16_t session, uint16_t flags,
+ const std::string& path) override;
+ std::vector<uint8_t> read(uint16_t session, uint32_t offset,
+ uint32_t requestedSize) override;
+ bool write(uint16_t session, uint32_t offset,
+ const std::vector<uint8_t>& data) override;
+ bool commit(uint16_t session, const std::vector<uint8_t>& data) override;
+ bool close(uint16_t session) override;
+ bool stat(uint16_t session, struct BlobMeta* meta) override;
+ bool expire(uint16_t session) override;
+
+ constexpr static char supportedPath[] = "/dev/fake/command";
+
+ private:
+ ExampleBlob* getSession(uint16_t id);
+
+ std::unordered_map<uint16_t, ExampleBlob> sessions;
+};
+
+} // namespace blobs