2020-10-09 19:35:46 +02:00
import eventManager from 'lib/eventManager' ;
import { Notification } from 'lib/models/Alarm' ;
import shim from 'lib/shim' ;
2017-11-28 20:47:41 +02:00
const notifier = require ( 'node-notifier' ) ;
2020-10-09 19:35:46 +02:00
const bridge = require ( 'electron' ) . remote . require ( './bridge' ) . default ;
interface Options {
appName : string ,
}
export default class AlarmServiceDriverNode {
2017-11-28 20:47:41 +02:00
2020-10-09 19:35:46 +02:00
private appName_ :string ;
private notifications_ :any = { } ;
private service_ :any = null ;
constructor ( options :Options ) {
2017-11-28 20:47:41 +02:00
// Note: appName is required to get the notification to work. It must be the same as the appId defined in package.json
// https://github.com/mikaelbr/node-notifier/issues/144#issuecomment-319324058
this . appName_ = options . appName ;
2019-10-02 20:21:42 +02:00
}
2020-10-09 19:35:46 +02:00
setService ( s :any ) {
2019-10-02 20:21:42 +02:00
this . service_ = s ;
}
logger() {
return this . service_ . logger ( ) ;
2017-11-28 02:22:38 +02:00
}
hasPersistentNotifications() {
return false ;
}
2020-10-09 19:35:46 +02:00
notificationIsSet ( id :string ) {
2017-11-28 02:22:38 +02:00
return id in this . notifications_ ;
}
2020-10-09 19:35:46 +02:00
async clearNotification ( id :string ) {
2017-11-28 02:22:38 +02:00
if ( ! this . notificationIsSet ( id ) ) return ;
2020-10-09 19:35:46 +02:00
shim . clearTimeout ( this . notifications_ [ id ] . timeoutId ) ;
2017-11-28 02:22:38 +02:00
delete this . notifications_ [ id ] ;
2017-11-28 00:50:46 +02:00
}
2019-07-29 15:43:53 +02:00
2020-10-09 19:35:46 +02:00
async scheduleNotification ( notification :Notification ) {
2017-11-28 02:22:38 +02:00
const now = Date . now ( ) ;
const interval = notification . date . getTime ( ) - now ;
if ( interval < 0 ) return ;
2017-11-28 00:50:46 +02:00
2018-12-08 01:42:29 +02:00
if ( isNaN ( interval ) ) {
2019-09-19 23:51:18 +02:00
throw new Error ( ` Trying to create a notification from an invalid object: ${ JSON . stringify ( notification ) } ` ) ;
2018-12-08 01:42:29 +02:00
}
2019-10-02 20:21:42 +02:00
this . logger ( ) . info ( ` AlarmServiceDriverNode::scheduleNotification: Notification ${ notification . id } with interval: ${ interval } ms ` ) ;
2020-10-09 19:35:46 +02:00
if ( this . notifications_ [ notification . id ] ) shim . clearTimeout ( this . notifications_ [ notification . id ] . timeoutId ) ;
2019-10-02 20:21:42 +02:00
let timeoutId = null ;
// Note: setTimeout will break for values larger than Number.MAX_VALUE - in which case the timer
// will fire immediately. So instead, if the interval is greater than a set max, reschedule after
// that max interval.
// https://stackoverflow.com/questions/3468607/why-does-settimeout-break-for-large-millisecond-delay-values/3468699
const maxInterval = 60 * 60 * 1000 ;
if ( interval >= maxInterval ) {
this . logger ( ) . info ( ` AlarmServiceDriverNode::scheduleNotification: Notification interval is greater than ${ maxInterval } ms - will reschedule in ${ maxInterval } ms ` ) ;
2020-10-09 19:35:46 +02:00
timeoutId = shim . setTimeout ( ( ) = > {
2019-10-02 20:21:42 +02:00
if ( ! this . notifications_ [ notification . id ] ) {
this . logger ( ) . info ( ` AlarmServiceDriverNode::scheduleNotification: Notification ${ notification . id } has been deleted - not rescheduling it ` ) ;
return ;
}
this . scheduleNotification ( this . notifications_ [ notification . id ] ) ;
} , maxInterval ) ;
} else {
2020-10-09 19:35:46 +02:00
timeoutId = shim . setTimeout ( ( ) = > {
const o :any = {
2019-10-02 20:21:42 +02:00
appID : this.appName_ ,
title : notification.title ,
icon : ` ${ bridge ( ) . electronApp ( ) . buildDir ( ) } /icons/512x512.png ` ,
} ;
if ( 'body' in notification ) o . message = notification . body ;
2019-12-18 12:22:01 +02:00
// Message is required on Windows 7 however we don't want to repeat the title so
// make it an empty string.
// https://github.com/laurent22/joplin/issues/2144
if ( ! o . message ) o . message = '-' ;
2019-10-02 20:21:42 +02:00
this . logger ( ) . info ( 'AlarmServiceDriverNode::scheduleNotification: Triggering notification:' , o ) ;
2020-10-09 19:35:46 +02:00
notifier . notify ( o , ( error :any , response :any ) = > {
2019-10-02 20:21:42 +02:00
this . logger ( ) . info ( 'AlarmServiceDriverNode::scheduleNotification: node-notifier response:' , error , response ) ;
} ) ;
this . clearNotification ( notification . id ) ;
2020-10-09 19:35:46 +02:00
eventManager . emit ( 'noteAlarmTrigger' , { noteId : notification.noteId } ) ;
2019-10-02 20:21:42 +02:00
} , interval ) ;
}
2017-11-28 20:47:41 +02:00
this . notifications_ [ notification . id ] = Object . assign ( { } , notification ) ;
this . notifications_ [ notification . id ] . timeoutId = timeoutId ;
2017-11-28 00:50:46 +02:00
}
}