11use std:: { error:: Error , fmt} ;
22
3- use log:: warn;
3+ use log:: { debug , warn} ;
44use sea_orm:: { DbConn , DbErr , EnumIter } ;
55
66use super :: repository as token_repository;
@@ -202,18 +202,27 @@ impl NotificationManager {
202202
203203 let rich_content = Self :: avatar_rich_content ( ctx, profile. avatar ) . await ;
204204
205- self . send_to_identity (
206- ctx,
207- & reply_recipient,
208- NotificationData {
209- collapse_id : collapse_id. to_owned ( ) ,
210- title,
211- body,
212- data,
213- rich_content,
214- } ,
215- )
216- . await ?;
205+ debug ! ( "Firing reply notification: from={author} to={reply_recipient} key={key:?}" ) ;
206+
207+ let response = self
208+ . send_to_identity (
209+ ctx,
210+ & reply_recipient,
211+ NotificationData {
212+ collapse_id : collapse_id. to_owned ( ) ,
213+ title,
214+ body,
215+ data,
216+ rich_content,
217+ } ,
218+ )
219+ . await ?;
220+
221+ if let Some ( errors) = Self :: ticket_errors ( & response) {
222+ warn ! (
223+ "Reply notification errors: from={author} to={reply_recipient} key={key:?} errors=[{errors}]"
224+ ) ;
225+ }
217226
218227 Ok ( ( ) )
219228 }
@@ -247,18 +256,31 @@ impl NotificationManager {
247256
248257 let rich_content = Self :: avatar_rich_content ( ctx, profile. avatar ) . await ;
249258
250- self . send_to_identity (
251- ctx,
252- & follow. identity ,
253- NotificationData {
254- collapse_id : collapse_id. to_owned ( ) ,
255- title,
256- body : "Followed you" . to_string ( ) ,
257- data,
258- rich_content,
259- } ,
260- )
261- . await ?;
259+ debug ! (
260+ "Firing follow notification: from={author} to={} key={key:?}" ,
261+ follow. identity
262+ ) ;
263+
264+ let response = self
265+ . send_to_identity (
266+ ctx,
267+ & follow. identity ,
268+ NotificationData {
269+ collapse_id : collapse_id. to_owned ( ) ,
270+ title,
271+ body : "Followed you" . to_string ( ) ,
272+ data,
273+ rich_content,
274+ } ,
275+ )
276+ . await ?;
277+
278+ if let Some ( errors) = Self :: ticket_errors ( & response) {
279+ warn ! (
280+ "Follow notification errors: from={author} to={} key={key:?} errors=[{errors}]" ,
281+ follow. identity
282+ ) ;
283+ }
262284
263285 Ok ( ( ) )
264286 }
@@ -310,6 +332,29 @@ impl NotificationManager {
310332 format ! ( "{cdn_url}/blob/{}_{}" , digest. r#type, hex)
311333 }
312334
335+ /// The error details of any failed tickets in a push response,
336+ /// comma-separated, or `None` when every ticket succeeded. Lets callers
337+ /// log failures while staying silent on success.
338+ fn ticket_errors ( response : & ExpoPushResponse ) -> Option < String > {
339+ let errors: Vec < & str > = response
340+ . data
341+ . iter ( )
342+ . filter ( |ticket| ticket. status == "error" )
343+ . map ( |ticket| {
344+ ticket
345+ . details
346+ . as_ref ( )
347+ . and_then ( |details| details. error . as_deref ( ) )
348+ . unwrap_or ( "unknown error" )
349+ } )
350+ // DeviceNotRegistered is already handled by
351+ // clean_unregistered_push_tokens
352+ . filter ( |error| * error != "DeviceNotRegistered" )
353+ . collect ( ) ;
354+
355+ ( !errors. is_empty ( ) ) . then ( || errors. join ( "," ) )
356+ }
357+
313358 /// Sends a push notification to every authorized key of an identity that
314359 /// has a registered token. Tokens reported as invalid by the push service
315360 /// are unregistered as part of the send.
@@ -318,7 +363,7 @@ impl NotificationManager {
318363 ctx : & Context ,
319364 identity : & str ,
320365 notification : NotificationData ,
321- ) -> Result < ( ) , NotificationError > {
366+ ) -> Result < ExpoPushResponse , NotificationError > {
322367 let authorized_keys = ctx. polycentric . authorized_keys ( identity) . await ;
323368
324369 let mut rows = vec ! [ ] ;
@@ -341,7 +386,7 @@ impl NotificationManager {
341386 }
342387
343388 if expo_tokens. is_empty ( ) {
344- return Ok ( ( ) ) ;
389+ return Ok ( ExpoPushResponse { data : vec ! [ ] } ) ;
345390 }
346391
347392 let expo_tokens_raw: Vec < String > = expo_tokens. iter ( ) . map ( |item| item. 1 . clone ( ) ) . collect ( ) ;
@@ -360,17 +405,17 @@ impl NotificationManager {
360405 . post_requests ( vec ! [ expo_push_request] )
361406 . await ?;
362407
363- self . clean_unregistered_push_tokens ( ctx, response, expo_tokens)
408+ self . clean_unregistered_push_tokens ( ctx, & response, expo_tokens)
364409 . await ?;
365410
366- Ok ( ( ) )
411+ Ok ( response )
367412 }
368413
369414 /// Removes any tokens from a given batch which are no longer registered from the database
370415 async fn clean_unregistered_push_tokens (
371416 & self ,
372417 ctx : & Context ,
373- response : ExpoPushResponse ,
418+ response : & ExpoPushResponse ,
374419 expo_tokens : Vec < ( PublicKey , String ) > ,
375420 ) -> Result < ( ) , NotificationError > {
376421 if response. data . len ( ) != expo_tokens. len ( ) {
@@ -639,6 +684,7 @@ mod tests {
639684 service : PushService :: Expo . as_ref ( ) . to_string ( ) ,
640685 token : token. to_string ( ) ,
641686 created_at : time:: PrimitiveDateTime :: MIN ,
687+ updated_at : time:: PrimitiveDateTime :: MIN ,
642688 }
643689 }
644690
0 commit comments