Skip to content

Commit a279801

Browse files
ref(dif): Put hash in ChunkedDifRequest
Putting the hash in the `ChunkedDifRequest` allows us to avoid needing to transform objects into tuples with a `ChunkedDifRequest` and a hash. With this change, we can greatly simplify the API for creating a `ChunkedDifRequest` and an `AssembleDifRequest`
1 parent e22107b commit a279801

File tree

4 files changed

+95
-54
lines changed

4 files changed

+95
-54
lines changed

src/api/data_types/chunking/dif.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ pub struct ChunkedDifRequest<'a> {
1414
#[serde(skip_serializing_if = "Option::is_none")]
1515
pub debug_id: Option<DebugId>,
1616
pub chunks: &'a [Digest],
17+
#[serde(skip)]
18+
hash: Digest,
19+
}
20+
21+
impl<'a> ChunkedDifRequest<'a> {
22+
/// Create a new ChunkedDifRequest with the given name, chunk hashes,
23+
/// and total hash for the entire file.
24+
pub fn new(name: &'a str, chunks: &'a [Digest], hash: Digest) -> Self {
25+
Self {
26+
name,
27+
chunks,
28+
hash,
29+
debug_id: None,
30+
}
31+
}
32+
33+
/// Set the provided debug_id on the request, or clear it if
34+
/// `None` is passed.
35+
pub fn with_debug_id(mut self, debug_id: Option<DebugId>) -> Self {
36+
self.debug_id = debug_id;
37+
self
38+
}
1739
}
1840

1941
#[derive(Debug, Deserialize)]
@@ -25,5 +47,40 @@ pub struct ChunkedDifResponse {
2547
pub dif: Option<DebugInfoFile>,
2648
}
2749

28-
pub type AssembleDifsRequest<'a> = HashMap<Digest, ChunkedDifRequest<'a>>;
50+
#[derive(Debug, Serialize)]
51+
#[serde(transparent)]
52+
pub struct AssembleDifsRequest<'a>(HashMap<Digest, ChunkedDifRequest<'a>>);
53+
54+
impl AssembleDifsRequest<'_> {
55+
/// Strips the debug_id from all requests in the request. We need
56+
/// to strip the debug_ids whenever the server does not support chunked
57+
/// uploading of PDBs, to maintain backwards compatibility. The
58+
/// calling code is responsible for calling this function when needed.
59+
///
60+
/// See: https://github.com/getsentry/sentry-cli/issues/980
61+
/// See: https://github.com/getsentry/sentry-cli/issues/1056
62+
pub fn strip_debug_ids(&mut self) {
63+
for r in self.0.values_mut() {
64+
r.debug_id = None;
65+
}
66+
}
67+
}
68+
69+
impl<'a, T> FromIterator<T> for AssembleDifsRequest<'a>
70+
where
71+
T: Into<ChunkedDifRequest<'a>>,
72+
{
73+
fn from_iter<I>(iter: I) -> Self
74+
where
75+
I: IntoIterator<Item = T>,
76+
{
77+
Self(
78+
iter.into_iter()
79+
.map(|obj| obj.into())
80+
.map(|r| (r.hash, r))
81+
.collect(),
82+
)
83+
}
84+
}
85+
2986
pub type AssembleDifsResponse = HashMap<Digest, ChunkedDifResponse>;

src/utils/chunks/types.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use std::fmt::{Display, Formatter, Result as FmtResult};
44

55
use anyhow::Result;
66
use sha1_smol::Digest;
7+
use symbolic::common::DebugId;
78

9+
use crate::api::ChunkedDifRequest;
810
use crate::utils::chunks::Chunk;
911
use crate::utils::fs;
1012

@@ -16,6 +18,10 @@ pub type MissingObjectsInfo<'m, T> = (Vec<&'m Chunked<T>>, Vec<Chunk<'m>>);
1618
pub trait Assemblable {
1719
/// Returns the name of the object.
1820
fn name(&self) -> &str;
21+
22+
/// Returns the debug ID of the object.
23+
/// Types which do not have a debug ID should return `None`.
24+
fn debug_id(&self) -> Option<DebugId>;
1925
}
2026

2127
/// Chunked arbitrary data with computed SHA1 checksums.
@@ -94,4 +100,18 @@ where
94100
fn name(&self) -> &str {
95101
self.object().name()
96102
}
103+
104+
fn debug_id(&self) -> Option<DebugId> {
105+
self.object().debug_id()
106+
}
107+
}
108+
109+
impl<'c, T> From<&'c Chunked<T>> for ChunkedDifRequest<'c>
110+
where
111+
T: Assemblable,
112+
{
113+
fn from(value: &'c Chunked<T>) -> Self {
114+
Self::new(value.name(), value.chunk_hashes(), value.checksum())
115+
.with_debug_id(value.debug_id())
116+
}
97117
}

src/utils/dif_upload.rs

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use zip::result::ZipError;
3333
use zip::{write::FileOptions, ZipArchive, ZipWriter};
3434

3535
use crate::api::{
36-
Api, ChunkUploadCapability, ChunkUploadOptions, ChunkedDifRequest, ChunkedFileState,
36+
Api, AssembleDifsRequest, ChunkUploadCapability, ChunkUploadOptions, ChunkedFileState,
3737
};
3838
use crate::config::Config;
3939
use crate::constants::{DEFAULT_MAX_DIF_SIZE, DEFAULT_MAX_WAIT};
@@ -309,38 +309,9 @@ impl Assemblable for DifMatch<'_> {
309309
fn name(&self) -> &str {
310310
self.file_name()
311311
}
312-
}
313-
314-
/// A tuple which can be collected into a mapping of checksums to
315-
/// `ChunkedDifRequest`s. The collected mapping can be sent in a
316-
/// request to the assemble endpoint.
317-
type AssembleRequest<'a> = (Digest, ChunkedDifRequest<'a>);
318-
319-
trait IntoAssembleRequest {
320-
/// Creates an `AssembleRequest` tuple for this object.
321-
fn assemble_request(&self, with_debug_id: bool) -> AssembleRequest<'_>;
322-
}
323312

324-
impl IntoAssembleRequest for Chunked<DifMatch<'_>> {
325-
// Some(...) for debug_id can only be done if the ChunkedUploadCapability::Pdbs is
326-
// present, which is kind of a protocol bug. Not supplying it means more recent
327-
// sentry-cli versions keep working with ancient versions of sentry by not
328-
// triggering this protocol bug in most common situations.
329-
// See: https://github.com/getsentry/sentry-cli/issues/980
330-
// See: https://github.com/getsentry/sentry-cli/issues/1056
331-
fn assemble_request(&self, with_debug_id: bool) -> AssembleRequest<'_> {
332-
(
333-
self.checksum(),
334-
ChunkedDifRequest {
335-
name: self.object().file_name(),
336-
debug_id: if with_debug_id {
337-
self.object().debug_id
338-
} else {
339-
None
340-
},
341-
chunks: self.chunk_hashes(),
342-
},
343-
)
313+
fn debug_id(&self) -> Option<DebugId> {
314+
self.debug_id
344315
}
345316
}
346317

@@ -1260,14 +1231,15 @@ fn try_assemble<'m, T>(
12601231
options: &DifUpload,
12611232
) -> Result<MissingObjectsInfo<'m, T>>
12621233
where
1263-
T: AsRef<[u8]>,
1264-
Chunked<T>: IntoAssembleRequest,
1234+
T: AsRef<[u8]> + Assemblable,
12651235
{
12661236
let api = Api::current();
1267-
let request = objects
1268-
.iter()
1269-
.map(|d| d.assemble_request(options.pdbs_allowed))
1270-
.collect();
1237+
let mut request: AssembleDifsRequest<'_> = objects.iter().collect();
1238+
1239+
if !options.pdbs_allowed {
1240+
request.strip_debug_ids();
1241+
}
1242+
12711243
let response = api
12721244
.authenticated()?
12731245
.assemble_difs(&options.org, &options.project, &request)?;
@@ -1405,7 +1377,6 @@ fn poll_assemble<T>(
14051377
) -> Result<(Vec<DebugInfoFile>, bool)>
14061378
where
14071379
T: Display + Assemblable,
1408-
Chunked<T>: IntoAssembleRequest,
14091380
{
14101381
let progress_style = ProgressStyle::default_bar().template(
14111382
"{prefix:.dim} Processing files...\
@@ -1419,10 +1390,11 @@ where
14191390

14201391
let assemble_start = Instant::now();
14211392

1422-
let request = chunked_objects
1423-
.iter()
1424-
.map(|d| d.assemble_request(options.pdbs_allowed))
1425-
.collect();
1393+
let mut request: AssembleDifsRequest<'_> = chunked_objects.iter().copied().collect();
1394+
if !options.pdbs_allowed {
1395+
request.strip_debug_ids();
1396+
}
1397+
14261398
let response = loop {
14271399
let response =
14281400
api.authenticated()?

src/utils/proguard_upload.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,10 @@ impl ChunkedMapping {
5858

5959
impl<'a> From<&'a ChunkedMapping> for ChunkedDifRequest<'a> {
6060
fn from(value: &'a ChunkedMapping) -> Self {
61-
ChunkedDifRequest {
62-
name: &value.file_name,
63-
debug_id: None,
64-
chunks: &value.chunk_hashes,
65-
}
61+
ChunkedDifRequest::new(&value.file_name, &value.chunk_hashes, value.hash)
6662
}
6763
}
6864

69-
fn to_assemble(chunked: &ChunkedMapping) -> (Digest, ChunkedDifRequest<'_>) {
70-
(chunked.hash, chunked.into())
71-
}
72-
7365
/// Uploads a set of Proguard mappings to Sentry.
7466
/// Blocks until the mappings have been assembled (up to ASSEMBLE_POLL_TIMEOUT).
7567
/// Returns an error if the mappings fail to assemble, or if the timeout is reached.
@@ -99,7 +91,7 @@ pub fn chunk_upload(
9991

10092
println!("Waiting for server to assemble uploaded mappings...");
10193

102-
let assemble_request = chunked_mappings.iter().map(to_assemble).collect();
94+
let assemble_request = chunked_mappings.iter().collect();
10395
let start = Instant::now();
10496
while Instant::now().duration_since(start) < ASSEMBLE_POLL_TIMEOUT {
10597
let all_assembled = Api::current()

0 commit comments

Comments
 (0)