diff --git a/ElectronClient/app/package-lock.json b/ElectronClient/app/package-lock.json index 63d58aafb..4d09d82f5 100644 --- a/ElectronClient/app/package-lock.json +++ b/ElectronClient/app/package-lock.json @@ -3956,6 +3956,11 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==" + }, "is2": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/is2/-/is2-0.0.9.tgz", @@ -4826,14 +4831,22 @@ } }, "node-notifier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", - "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz", + "integrity": "sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw==", "requires": { "growly": "^1.3.0", - "semver": "^5.4.1", + "is-wsl": "^2.1.1", + "semver": "^6.3.0", "shellwords": "^0.1.1", - "which": "^1.3.0" + "which": "^1.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "node-pre-gyp": { diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json index 4a8cb6600..eaee4ed9b 100644 --- a/ElectronClient/app/package.json +++ b/ElectronClient/app/package.json @@ -130,7 +130,7 @@ "multiparty": "^4.2.1", "mustache": "^3.0.1", "node-fetch": "^1.7.3", - "node-notifier": "^5.2.1", + "node-notifier": "^6.0.0", "promise": "^8.0.1", "query-string": "^5.1.1", "react": "^16.4.0", diff --git a/ReactNativeClient/lib/services/AlarmService.js b/ReactNativeClient/lib/services/AlarmService.js index ba68af8bc..b889fefbd 100644 --- a/ReactNativeClient/lib/services/AlarmService.js +++ b/ReactNativeClient/lib/services/AlarmService.js @@ -4,6 +4,8 @@ const Alarm = require('lib/models/Alarm.js'); class AlarmService { static setDriver(v) { this.driver_ = v; + + if (this.driver_.setService) this.driver_.setService(this); } static driver() { diff --git a/ReactNativeClient/lib/services/AlarmServiceDriverNode.js b/ReactNativeClient/lib/services/AlarmServiceDriverNode.js index a903d3b22..13cca6504 100644 --- a/ReactNativeClient/lib/services/AlarmServiceDriverNode.js +++ b/ReactNativeClient/lib/services/AlarmServiceDriverNode.js @@ -1,4 +1,5 @@ const notifier = require('node-notifier'); +const { bridge } = require('electron').remote.require('./bridge'); class AlarmServiceDriverNode { constructor(options) { @@ -6,6 +7,15 @@ class AlarmServiceDriverNode { // https://github.com/mikaelbr/node-notifier/issues/144#issuecomment-319324058 this.appName_ = options.appName; this.notifications_ = {}; + this.service_ = null; + } + + setService(s) { + this.service_ = s; + } + + logger() { + return this.service_.logger(); } hasPersistentNotifications() { @@ -31,15 +41,46 @@ class AlarmServiceDriverNode { throw new Error(`Trying to create a notification from an invalid object: ${JSON.stringify(notification)}`); } - const timeoutId = setTimeout(() => { - const o = { - appName: this.appName_, - title: notification.title, - }; - if ('body' in notification) o.message = notification.body; - notifier.notify(o); - this.clearNotification(notification.id); - }, interval); + this.logger().info(`AlarmServiceDriverNode::scheduleNotification: Notification ${notification.id} with interval: ${interval}ms`); + + if (this.notifications_[notification.id]) clearTimeout(this.notifications_[notification.id].timeoutId); + + 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`); + + timeoutId = setTimeout(() => { + 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 { + timeoutId = setTimeout(() => { + const o = { + appID: this.appName_, + title: notification.title, + icon: `${bridge().electronApp().buildDir()}/icons/512x512.png`, + }; + if ('body' in notification) o.message = notification.body; + + this.logger().info('AlarmServiceDriverNode::scheduleNotification: Triggering notification:', o); + + notifier.notify(o, (error, response) => { + this.logger().info('AlarmServiceDriverNode::scheduleNotification: node-notifier response:', error, response); + }); + + this.clearNotification(notification.id); + }, interval); + } this.notifications_[notification.id] = Object.assign({}, notification); this.notifications_[notification.id].timeoutId = timeoutId;