From fab1b26f88edcf00fa01d9603bf3f990d9744eeb Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 29 Oct 2025 09:28:48 -0400 Subject: [PATCH 1/2] meta: Add cargo metadata and a client readme --- README.md | 6 ++++++ objectstore-client/Cargo.toml | 7 +++++++ objectstore-client/README.md | 24 ++++++++++++++++++++++++ objectstore-client/src/get.rs | 16 ++++++++++++++++ objectstore-client/src/lib.rs | 25 +++++++++++++++++++++---- objectstore-server/Cargo.toml | 6 ++++++ objectstore-service/Cargo.toml | 6 ++++++ objectstore-types/Cargo.toml | 6 ++++++ stresstest/Cargo.toml | 6 ++++++ 9 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 objectstore-client/README.md diff --git a/README.md b/README.md index b173f95e..f9e7e0c7 100644 --- a/README.md +++ b/README.md @@ -191,3 +191,9 @@ cargo run --release -p stresstest -- -c stresstest/config/example.yaml Similar to the objectstore server, you can find example configuration files in the `config` subfolder. Copy and save your own files there, as they will not be tracked by git. + +## License + +Like Sentry, Objectstore is licensed under the FSL. See the `LICENSE.md` file +and [this blog post](https://blog.sentry.io/introducing-the-functional-source-license-freedom-without-free-riding/) +for more information. diff --git a/objectstore-client/Cargo.toml b/objectstore-client/Cargo.toml index 99175445..66a04218 100644 --- a/objectstore-client/Cargo.toml +++ b/objectstore-client/Cargo.toml @@ -1,7 +1,14 @@ [package] name = "objectstore-client" +authors = ["Sentry "] +description = "Client SDK for Objectstore, the Sentry object storage platform" +homepage = "https://getsentry.github.io/objectstore/" +repository = "https://github.com/getsentry/objectstore" +license-file = "../LICENSE.md" version = "0.1.0" edition = "2024" +rust-version = "1.89" +publish = true [dependencies] anyhow = { workspace = true } diff --git a/objectstore-client/README.md b/objectstore-client/README.md new file mode 100644 index 00000000..5a94016e --- /dev/null +++ b/objectstore-client/README.md @@ -0,0 +1,24 @@ +# Objectstore Client + +The client is used to interface with the objectstore backend. It handles +responsibilities like transparent compression, and making sure that uploads and +downloads are done as efficiently as possible. + +## Usage + +```rust +use objectstore_client::ClientBuilder; + +let client = ClientBuilder::new("http://localhost:8888/", "my-usecase")? + .for_organization(42); + +let id = client.put("hello world").send().await?; +let object = client.get(&id.key).send().await?.expect("object to exist"); +assert_eq!(object.payload().await?, "hello world"); +``` + +## License + +Like Sentry, Objectstore is licensed under the FSL. See the `LICENSE.md` file +and [this blog post](https://blog.sentry.io/introducing-the-functional-source-license-freedom-without-free-riding/) +for more information. diff --git a/objectstore-client/src/get.rs b/objectstore-client/src/get.rs index d8f76bca..4ae020a8 100644 --- a/objectstore-client/src/get.rs +++ b/objectstore-client/src/get.rs @@ -1,6 +1,7 @@ use std::{fmt, io}; use async_compression::tokio::bufread::ZstdDecoder; +use bytes::BytesMut; use futures_util::{StreamExt, TryStreamExt}; use objectstore_types::Metadata; use reqwest::StatusCode; @@ -19,6 +20,21 @@ pub struct GetResult { /// The response stream. pub stream: ClientStream, } + +impl GetResult { + /// Loads the object payload fully into memory. + pub async fn payload(self) -> anyhow::Result { + let bytes: BytesMut = self.stream.try_collect().await?; + Ok(bytes.freeze()) + } + + /// Loads the object payload fully into memory and interprets it as UTF-8 text. + pub async fn text(self) -> anyhow::Result { + let bytes = self.payload().await?; + Ok(String::from_utf8(bytes.to_vec())?) + } +} + impl fmt::Debug for GetResult { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("GetResult") diff --git a/objectstore-client/src/lib.rs b/objectstore-client/src/lib.rs index 8ffb9e74..27d4b587 100644 --- a/objectstore-client/src/lib.rs +++ b/objectstore-client/src/lib.rs @@ -1,8 +1,25 @@ -//! The Storage Client +//! # Objectstore Client //! -//! The Client is used to interface with the objectstore backend. -//! It handles responsibilities like transparent compression, and making sure that -//! uploads and downloads are done as efficiently as possible. +//! The client is used to interface with the objectstore backend. It handles responsibilities like +//! transparent compression, and making sure that uploads and downloads are done as efficiently as +//! possible. +//! +//! ## Usage +//! +//! ``` +//! use objectstore_client::ClientBuilder; +//! +//! #[tokio::main] +//! # async fn main() -> anyhow::Result<()> { +//! let client = ClientBuilder::new("http://localhost:8888/", "my-usecase")? +//! .for_organization(42); +//! +//! let id = client.put("hello world").send().await?; +//! let object = client.get(&id.key).send().await?.expect("object to exist"); +//! assert_eq!(object.payload().await?, "hello world"); +//! # Ok(()) +//! # } +//! ``` #![warn(missing_docs)] #![warn(missing_debug_implementations)] diff --git a/objectstore-server/Cargo.toml b/objectstore-server/Cargo.toml index 7a4e2c92..5a01d8cb 100644 --- a/objectstore-server/Cargo.toml +++ b/objectstore-server/Cargo.toml @@ -1,8 +1,14 @@ [package] name = "objectstore-server" +authors = ["Sentry "] +description = "Web server application of Objectstore, the Sentry object storage platform" +homepage = "https://getsentry.github.io/objectstore/" +repository = "https://github.com/getsentry/objectstore" +license-file = "../LICENSE.md" version = "0.1.0" edition = "2024" build = "build.rs" +publish = false [dependencies] anyhow = { workspace = true } diff --git a/objectstore-service/Cargo.toml b/objectstore-service/Cargo.toml index 82254c5a..dd88a9e3 100644 --- a/objectstore-service/Cargo.toml +++ b/objectstore-service/Cargo.toml @@ -1,7 +1,13 @@ [package] name = "objectstore-service" +authors = ["Sentry "] +description = "Storage and backend logic of Objectstore, the Sentry object storage platform" +homepage = "https://getsentry.github.io/objectstore/" +repository = "https://github.com/getsentry/objectstore" +license-file = "../LICENSE.md" version = "0.1.0" edition = "2024" +publish = false [dependencies] anyhow = { workspace = true } diff --git a/objectstore-types/Cargo.toml b/objectstore-types/Cargo.toml index a81477fd..9f966e07 100644 --- a/objectstore-types/Cargo.toml +++ b/objectstore-types/Cargo.toml @@ -1,7 +1,13 @@ [package] name = "objectstore-types" +authors = ["Sentry "] +description = "Shared types for the Objectstore client and server" +homepage = "https://getsentry.github.io/objectstore/" +repository = "https://github.com/getsentry/objectstore" +license-file = "../LICENSE.md" version = "0.1.0" edition = "2024" +publish = false [dependencies] anyhow = { workspace = true } diff --git a/stresstest/Cargo.toml b/stresstest/Cargo.toml index 4dd68a85..66f424b5 100644 --- a/stresstest/Cargo.toml +++ b/stresstest/Cargo.toml @@ -1,7 +1,13 @@ [package] name = "stresstest" +authors = ["Sentry "] +description = "Tool for generating file storage load against Objectstore servers" +homepage = "https://getsentry.github.io/objectstore/" +repository = "https://github.com/getsentry/objectstore" +license-file = "../LICENSE.md" version = "0.1.0" edition = "2024" +publish = false [dependencies] anyhow = { workspace = true } From 0a0e084c52d9dadaf73f9920ab8b4bbfd94bdaff Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 29 Oct 2025 09:34:30 -0400 Subject: [PATCH 2/2] test: Do not run the client doctest --- objectstore-client/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objectstore-client/src/lib.rs b/objectstore-client/src/lib.rs index 27d4b587..01d59e14 100644 --- a/objectstore-client/src/lib.rs +++ b/objectstore-client/src/lib.rs @@ -6,7 +6,7 @@ //! //! ## Usage //! -//! ``` +//! ```no_run //! use objectstore_client::ClientBuilder; //! //! #[tokio::main]