diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ce4bb3765..9c4e2c3875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Features + +- (snapshots) Compress preprod snapshot manifest with zstd ([#3336](https://github.com/getsentry/sentry-cli/pull/3336)) + ## 3.5.1 ### Internal Changes 🔧 diff --git a/Cargo.lock b/Cargo.lock index 3073b9181f..7fa7281372 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3702,6 +3702,7 @@ dependencies = [ "whoami", "windows-sys 0.59.0", "zip 2.4.2", + "zstd", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 87e4a8f3aa..99092a8382 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ walkdir = "2.3.2" which = "4.4.0" whoami = "1.5.2" zip = "2.4.2" +zstd = "0.13.3" data-encoding = "2.3.3" magic_string = "0.3.4" chrono-tz = "0.8.4" diff --git a/src/api/mod.rs b/src/api/mod.rs index b52d4cc4e0..24a3741844 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -42,6 +42,7 @@ use symbolic::common::DebugId; use symbolic::debuginfo::ObjectKind; use url::Url; use uuid::Uuid; +use zstd::Encoder as ZstdEncoder; use crate::api::errors::{ProjectRenamedError, RetryError}; use crate::config::{Auth, Config}; @@ -1020,7 +1021,9 @@ impl AuthenticatedApi<'_> { PathArg(org), PathArg(project) ); - self.post(&path, body) + self.request(Method::Post, &path)? + .with_zstd_json_body(body)? + .send() } /// Fetches upload options for snapshots. @@ -1360,6 +1363,30 @@ impl ApiRequest { Ok(self) } + pub fn with_zstd_json_body(mut self, body: &S) -> ApiResult { + let mut encoder = ZstdEncoder::new(Vec::new(), 0) + .map_err(|err| ApiError::with_source(ApiErrorKind::CompressionFailed, err))?; + + serde_json::to_writer(&mut encoder, &body).map_err(|err| { + let kind = if err.is_io() { + ApiErrorKind::CompressionFailed + } else { + ApiErrorKind::CannotSerializeAsJson + }; + ApiError::with_source(kind, err) + })?; + + let compressed = encoder + .finish() + .map_err(|err| ApiError::with_source(ApiErrorKind::CompressionFailed, err))?; + + debug!("zstd json body: {} bytes compressed", compressed.len()); + self.body = Some(compressed); + self.headers.append("Content-Type: application/json")?; + self.headers.append("Content-Encoding: zstd")?; + Ok(self) + } + pub fn with_body(mut self, body: Vec) -> Self { self.body = Some(body); self