@@ -18,6 +18,7 @@ export const _matchToken = Match.OneOf({ apn: String }, { gcm: String });
1818
1919const PUSH_TITLE_LIMIT = 65 ;
2020const PUSH_MESSAGE_BODY_LIMIT = 240 ;
21+ const PUSH_GATEWAY_MAX_ATTEMPTS = 5 ;
2122
2223type FCMCredentials = {
2324 type : string ;
@@ -185,8 +186,8 @@ class PushClass {
185186 logger . debug ( { msg : 'send to token' , token : app . token } ) ;
186187
187188 if ( 'apn' in app . token && app . token . apn ) {
188- const userToken = notification . voip ? app . voipToken : app . token . apn ;
189- const topic = notification . voip ? `${ app . appName } .voip` : app . appName ;
189+ const userToken = notification . useVoipToken ? app . voipToken : app . token . apn ;
190+ const topic = notification . useVoipToken ? `${ app . appName } .voip` : app . appName ;
190191
191192 countApn . push ( app . _id ) ;
192193 // Send to APN
@@ -254,7 +255,7 @@ class PushClass {
254255 service : 'apn' | 'gcm' ,
255256 token : string ,
256257 notification : Optional < GatewayNotification , 'uniqueId' > ,
257- tries = 0 ,
258+ retryOptions : { tries : number ; maxTries : number } = { tries : 0 , maxTries : PUSH_GATEWAY_MAX_ATTEMPTS } ,
258259 ) : Promise < void > {
259260 notification . uniqueId = this . options . uniqueId ;
260261
@@ -292,15 +293,17 @@ class PushClass {
292293 return ;
293294 }
294295
296+ const { tries, maxTries } = retryOptions ;
297+
295298 logger . error ( { msg : 'Error sending push to gateway' , tries, err : response } ) ;
296299
297- if ( tries <= 4 ) {
300+ if ( tries < maxTries ) {
298301 // [1, 2, 4, 8, 16] minutes (total 31)
299302 const ms = 60000 * Math . pow ( 2 , tries ) ;
300303
301304 logger . log ( { msg : 'Retrying push to gateway' , tries : tries + 1 , in : ms } ) ;
302305
303- setTimeout ( ( ) => this . sendGatewayPush ( gateway , service , token , notification , tries + 1 ) , ms ) ;
306+ setTimeout ( ( ) => this . sendGatewayPush ( gateway , service , token , notification , { tries : tries + 1 , maxTries } ) , ms ) ;
304307 }
305308 }
306309
@@ -325,40 +328,47 @@ class PushClass {
325328 }
326329
327330 const gatewayNotification = this . getGatewayNotificationData ( notification ) ;
331+ const retryOptions = {
332+ tries : 0 ,
333+ maxTries : notification . useVoipToken ? 1 : PUSH_GATEWAY_MAX_ATTEMPTS ,
334+ } ;
328335
329336 for ( const gateway of this . options . gateways ) {
330337 logger . debug ( { msg : 'send to token' , token : app . token } ) ;
331338
332339 if ( 'apn' in app . token && app . token . apn ) {
333- const token = notification . voip ? app . voipToken : app . token . apn ;
334- const topic = notification . voip ? `${ app . appName } .voip` : app . appName ;
340+ const token = notification . useVoipToken ? app . voipToken : app . token . apn ;
341+ const topic = notification . useVoipToken ? `${ app . appName } .voip` : app . appName ;
335342
336343 if ( token ) {
337344 countApn . push ( app . _id ) ;
338- return this . sendGatewayPush ( gateway , 'apn' , token , { topic, ...gatewayNotification } ) ;
345+ return this . sendGatewayPush ( gateway , 'apn' , token , { topic, ...gatewayNotification } , retryOptions ) ;
339346 }
340347 }
341348
342349 if ( 'gcm' in app . token && app . token . gcm ) {
343350 countGcm . push ( app . _id ) ;
344- return this . sendGatewayPush ( gateway , 'gcm' , app . token . gcm , gatewayNotification ) ;
351+ return this . sendGatewayPush ( gateway , 'gcm' , app . token . gcm , gatewayNotification , retryOptions ) ;
345352 }
346353 }
347354 }
348355
349- private async sendNotification ( notification : PendingPushNotification ) : Promise < { apn : string [ ] ; gcm : string [ ] } > {
356+ private async sendNotification (
357+ notification : PendingPushNotification ,
358+ options : { skipTokenId ?: IPushToken [ '_id' ] } = { } ,
359+ ) : Promise < { apn : string [ ] ; gcm : string [ ] } > {
350360 logger . debug ( { msg : 'Sending notification' , notification } ) ;
351361
352362 const countApn : string [ ] = [ ] ;
353363 const countGcm : string [ ] = [ ] ;
354364
355- if ( notification . from !== String ( notification . from ) ) {
365+ if ( notification . from && notification . from !== String ( notification . from ) ) {
356366 throw new Error ( 'Push.send: option "from" not a string' ) ;
357367 }
358- if ( notification . title !== String ( notification . title ) ) {
368+ if ( notification . title && notification . title !== String ( notification . title ) ) {
359369 throw new Error ( 'Push.send: option "title" not a string' ) ;
360370 }
361- if ( notification . text !== String ( notification . text ) ) {
371+ if ( notification . text && notification . text !== String ( notification . text ) ) {
362372 throw new Error ( 'Push.send: option "text" not a string' ) ;
363373 }
364374
@@ -368,7 +378,9 @@ class PushClass {
368378 userId : notification . userId ,
369379 } ) ;
370380
371- const appTokens = PushToken . findAllTokensByUserId ( notification . userId ) ;
381+ const appTokens = options . skipTokenId
382+ ? PushToken . findTokensByUserIdExceptId ( notification . userId , options . skipTokenId )
383+ : PushToken . findAllTokensByUserId ( notification . userId ) ;
372384
373385 for await ( const app of appTokens ) {
374386 logger . debug ( { msg : 'send to token' , token : app . token } ) ;
@@ -438,7 +450,7 @@ class PushClass {
438450 createdAt : Date ,
439451 createdBy : Match . OneOf ( String , null ) ,
440452 priority : Match . Optional ( Match . Integer ) ,
441- voip : Match . Optional ( Boolean ) ,
453+ useVoipToken : Match . Optional ( Boolean ) ,
442454 } ) ;
443455
444456 if ( ! notification . userId ) {
@@ -455,13 +467,13 @@ class PushClass {
455467 }
456468
457469 public async send ( options : IPushNotificationConfig ) {
458- const notification = {
470+ const notification : PendingPushNotification = {
459471 createdAt : new Date ( ) ,
460472 // createdBy is no longer used, but the gateway still expects it
461473 createdBy : '<SERVER>' ,
462474 sent : false ,
463475 sending : 0 ,
464- ...pick ( options , 'from' , 'userId' , 'payload' , 'badge' , 'sound' , 'notId' , 'priority' , 'voip ' ) ,
476+ ...pick ( options , 'from' , 'userId' , 'payload' , 'badge' , 'sound' , 'notId' , 'priority' , 'useVoipToken ' ) ,
465477 ...( options . title && { title : truncateString ( options . title , PUSH_TITLE_LIMIT ) } ) ,
466478 ...( options . text && { text : truncateString ( options . text , PUSH_MESSAGE_BODY_LIMIT ) } ) ,
467479
@@ -485,7 +497,7 @@ class PushClass {
485497 this . _validateDocument ( notification ) ;
486498
487499 try {
488- await this . sendNotification ( notification ) ;
500+ await this . sendNotification ( notification , pick ( options , 'skipTokenId' ) ) ;
489501 } catch ( error : any ) {
490502 logger . debug ( {
491503 msg : 'Could not send notification to user' ,
0 commit comments