@@ -163,6 +163,31 @@ impl<'s> Iterator for EnvelopeItemIter<'s> {
163
163
}
164
164
}
165
165
166
+ /// The items contained in an [`Envelope`].
167
+ ///
168
+ /// This may be a vector of [`EnvelopeItem`]s (the standard case)
169
+ /// or a binary blob.
170
+ #[ derive( Debug , Clone , PartialEq ) ]
171
+ enum Items {
172
+ EnvelopeItems ( Vec < EnvelopeItem > ) ,
173
+ Raw ( Vec < u8 > ) ,
174
+ }
175
+
176
+ impl Default for Items {
177
+ fn default ( ) -> Self {
178
+ Self :: EnvelopeItems ( Default :: default ( ) )
179
+ }
180
+ }
181
+
182
+ impl Items {
183
+ fn is_empty ( & self ) -> bool {
184
+ match self {
185
+ Items :: EnvelopeItems ( items) => items. is_empty ( ) ,
186
+ Items :: Raw ( bytes) => bytes. is_empty ( ) ,
187
+ }
188
+ }
189
+ }
190
+
166
191
/// A Sentry Envelope.
167
192
///
168
193
/// An Envelope is the data format that Sentry uses for Ingestion. It can contain
@@ -174,7 +199,7 @@ impl<'s> Iterator for EnvelopeItemIter<'s> {
174
199
#[ derive( Clone , Default , Debug , PartialEq ) ]
175
200
pub struct Envelope {
176
201
event_id : Option < Uuid > ,
177
- items : Vec < EnvelopeItem > ,
202
+ items : Items ,
178
203
}
179
204
180
205
impl Envelope {
@@ -188,6 +213,11 @@ impl Envelope {
188
213
where
189
214
I : Into < EnvelopeItem > ,
190
215
{
216
+ let Items :: EnvelopeItems ( ref mut items) = self . items else {
217
+ eprintln ! ( "WARNING: This envelope contains raw items. Adding an item is not supported." ) ;
218
+ return ;
219
+ } ;
220
+
191
221
let item = item. into ( ) ;
192
222
if self . event_id . is_none ( ) {
193
223
if let EnvelopeItem :: Event ( ref event) = item {
@@ -196,14 +226,17 @@ impl Envelope {
196
226
self . event_id = Some ( transaction. event_id ) ;
197
227
}
198
228
}
199
- self . items . push ( item) ;
229
+ items. push ( item) ;
200
230
}
201
231
202
232
/// Create an [`Iterator`] over all the [`EnvelopeItem`]s.
203
233
pub fn items ( & self ) -> EnvelopeItemIter {
204
- EnvelopeItemIter {
205
- inner : self . items . iter ( ) ,
206
- }
234
+ let inner = match & self . items {
235
+ Items :: EnvelopeItems ( items) => items. iter ( ) ,
236
+ Items :: Raw ( _) => [ ] . iter ( ) ,
237
+ } ;
238
+
239
+ EnvelopeItemIter { inner }
207
240
}
208
241
209
242
/// Returns the Envelopes Uuid, if any.
@@ -215,13 +248,14 @@ impl Envelope {
215
248
///
216
249
/// [`Event`]: struct.Event.html
217
250
pub fn event ( & self ) -> Option < & Event < ' static > > {
218
- self . items
219
- . iter ( )
220
- . filter_map ( |item| match item {
221
- EnvelopeItem :: Event ( event) => Some ( event) ,
222
- _ => None ,
223
- } )
224
- . next ( )
251
+ let Items :: EnvelopeItems ( ref items) = self . items else {
252
+ return None ;
253
+ } ;
254
+
255
+ items. iter ( ) . find_map ( |item| match item {
256
+ EnvelopeItem :: Event ( event) => Some ( event) ,
257
+ _ => None ,
258
+ } )
225
259
}
226
260
227
261
/// Filters the Envelope's [`EnvelopeItem`]s based on a predicate,
@@ -236,8 +270,12 @@ impl Envelope {
236
270
where
237
271
P : FnMut ( & EnvelopeItem ) -> bool ,
238
272
{
273
+ let Items :: EnvelopeItems ( items) = self . items else {
274
+ return None ;
275
+ } ;
276
+
239
277
let mut filtered = Envelope :: new ( ) ;
240
- for item in self . items {
278
+ for item in items {
241
279
if predicate ( & item) {
242
280
filtered. add_item ( item) ;
243
281
}
@@ -246,9 +284,9 @@ impl Envelope {
246
284
// filter again, removing attachments which do not make any sense without
247
285
// an event/transaction
248
286
if filtered. uuid ( ) . is_none ( ) {
249
- filtered
250
- . items
251
- . retain ( |item| ! matches ! ( item , EnvelopeItem :: Attachment ( .. ) ) )
287
+ if let Items :: EnvelopeItems ( ref mut items ) = filtered. items {
288
+ items. retain ( |item| ! matches ! ( item , EnvelopeItem :: Attachment ( .. ) ) )
289
+ }
252
290
}
253
291
254
292
if filtered. items . is_empty ( ) {
@@ -265,17 +303,21 @@ impl Envelope {
265
303
where
266
304
W : Write ,
267
305
{
268
- let mut item_buf = Vec :: new ( ) ;
269
-
270
306
// write the headers:
271
307
let event_id = self . uuid ( ) ;
272
308
match event_id {
273
309
Some ( uuid) => writeln ! ( writer, r#"{{"event_id":"{uuid}"}}"# ) ?,
274
310
_ => writeln ! ( writer, "{{}}" ) ?,
275
311
}
276
312
313
+ let items = match & self . items {
314
+ Items :: Raw ( bytes) => return writer. write_all ( bytes) . map ( |_| ( ) ) ,
315
+ Items :: EnvelopeItems ( items) => items,
316
+ } ;
317
+
318
+ let mut item_buf = Vec :: new ( ) ;
277
319
// write each item:
278
- for item in & self . items {
320
+ for item in items {
279
321
// we write them to a temporary buffer first, since we need their length
280
322
match item {
281
323
EnvelopeItem :: Event ( event) => serde_json:: to_writer ( & mut item_buf, event) ?,
@@ -340,6 +382,18 @@ impl Envelope {
340
382
Envelope :: from_slice ( & bytes)
341
383
}
342
384
385
+ /// Creates a new Envelope from path without attempting to parse anything.
386
+ ///
387
+ /// The resulting Envelope will have no `event_id` and the file contents will
388
+ /// be contained verbatim in the `items` field.
389
+ pub fn from_path_raw < P : AsRef < Path > > ( path : P ) -> Result < Self , EnvelopeError > {
390
+ let bytes = std:: fs:: read ( path) . map_err ( |_| EnvelopeError :: UnexpectedEof ) ?;
391
+ Ok ( Self {
392
+ event_id : None ,
393
+ items : Items :: Raw ( bytes) ,
394
+ } )
395
+ }
396
+
343
397
fn parse_header ( slice : & [ u8 ] ) -> Result < ( EnvelopeHeader , usize ) , EnvelopeError > {
344
398
let mut stream = serde_json:: Deserializer :: from_slice ( slice) . into_iter ( ) ;
345
399
0 commit comments