From 7342fa3979a0cd826ead1fc70bdb4107d3040120 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Fri, 19 Oct 2018 16:46:02 -0600 Subject: [PATCH 1/7] Implement attachments. - Allow 'file' to be passed into Pushover.send(). This can either be a filename (string) or an object ({name: 'asdf.png', data: Buffer}). If you pass in the object, you can overwrite the 'content-type' header by setting something like 'type: "image/bmp"'. This closes #23 and #20 --- README.md | 2 ++ lib/pushover.js | 83 +++++++++++++++++++++++++++++++++++++++++++++--- test/test_img.js | 45 ++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 test/test_img.js diff --git a/README.md b/README.md index d9f30ca..017a253 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ var msg = { title: "Well - this is fantastic", sound: 'magic' // optional priority: 1 // optional, + file: '/tmp/fancy_image.png' // optional + // see test/test_img.js for more examples of attaching images } for ( var i = 0, l = users.length; i < l; i++ ) { diff --git a/lib/pushover.js b/lib/pushover.js index 04c7964..4ed9a73 100644 --- a/lib/pushover.js +++ b/lib/pushover.js @@ -1,8 +1,10 @@ +var fs = require('fs') var https = require('https') var http = require('http') var url = require('url') var qs = require('querystring') var pUrl = 'https://api.pushover.net/1/messages.json' +var path = require('path') function setDefaults (o) { var def = [ @@ -26,8 +28,62 @@ function setDefaults (o) { return o } +function loadImage(imgPath) { + var o = {} + o.name = path.basename(imgPath) + o.data = fs.readFileSync(imgPath) + return o +} + + +function reqString2MP(rs, b, imgObj) { + var a = [] + var parts = [] + var o = qs.parse(rs) + + a.push(b) + + for (var p in o) { + if (o[p] !== '') { + a.push('Content-Disposition: form-data; name="' + p + '"') + a.push("") + a.push(o[p]) + a.push(b) + } + } + + if (imgObj) { + a.push('Content-Disposition: form-data; name="attachment"; filename="' + imgObj.name + '"') + if (imgObj.hasOwnProperty('type')) { + a.push('Content-Type: ' + imgObj.type) + } else { + a.push('Content-Type: application/octet-stream') + } + a.push('') + a.push('') + } else { + a.splice(-1, 1) + } + + var payload + if (imgObj) { + payload = Buffer.concat([ + Buffer.from(a.join('\r\n'), 'utf8'), + new Buffer(imgObj.data, 'binary'), + Buffer.from('\r\n' + b + '--\r\n', 'utf8') + ]) + } else { + payload = Buffer.concat([ + Buffer.from(a.join('\r\n'), 'utf8'), + Buffer.from(b + '--\r\n', 'utf8') + ]) + } + return payload +} + function Pushover (opts) { var self = this + this.boundary = "--" + Math.random().toString(36).substring(2) this.token = opts.token this.user = opts.user this.httpOptions = opts.httpOptions @@ -72,6 +128,7 @@ function Pushover (opts) { } } + Pushover.prototype.errors = function (d, res) { if (typeof d === 'string') { d = JSON.parse(d) @@ -125,13 +182,30 @@ Pushover.prototype.send = function (obj, fn) { var p for (p in obj) { - reqString[ p ] = obj[p] + if (obj[p] !== '') { + if (p !== 'file') { + reqString[ p ] = obj[p] + } + } } reqString = qs.stringify(reqString) + var mp + if (obj.file) { + if (typeof obj.file === 'string') { + mp = reqString2MP(reqString, self.boundary, loadImage(obj.file)) + } + if (typeof obj.file === 'object') { + mp = reqString2MP(reqString, self.boundary, obj.file) + } + } else { + mp = reqString2MP(reqString, self.boundary) + } + o.headers = { - 'Content-Length': reqString.length + 'Content-type': 'multipart/form-data; boundary=' + self.boundary.substring(2), + 'Content-Length': mp.length } var httpOpts = self.httpOptions || {} @@ -151,7 +225,7 @@ Pushover.prototype.send = function (obj, fn) { } var request - if (httpOpts.proxy && httpOpts.proxy !== '') { + if ((httpOpts.proxy && httpOpts.proxy !== '') || pUrl.match(/http:/)) { request = http.request } else { request = https.request @@ -187,7 +261,8 @@ Pushover.prototype.send = function (obj, fn) { if (self.debug) { console.log(reqString.replace(self.token, 'XXXXX').replace(self.user, 'XXXXX')) } - req.write(reqString) + + req.write(mp) req.end() } diff --git a/test/test_img.js b/test/test_img.js new file mode 100644 index 0000000..e224ad8 --- /dev/null +++ b/test/test_img.js @@ -0,0 +1,45 @@ +var Push = require('../lib/pushover.js') +var fs = require('fs') + +var p = new Push({ + user: process.env['PUSHOVER_USER'], + token: process.env['PUSHOVER_TOKEN'], + update_sounds: false, + debug: true +}) + +fs.readFile('test/test_img.png', function(err, data) { + var o = { + name: 'pushover.png', + data: data + } + + var msg = { + message: 'test from ' + process.argv[1], + sound: 'magic', + title: 'Image loaded async', + file: o + } + + p.send(msg, function (err, result, res) { + console.log('error', err) + console.log('result', result) + console.log('res.headers', res.headers) + // process.exit(0); + }) +}) + +// console.log( p ); +var msg = { + message: 'test from ' + process.argv[1], + sound: 'magic', + title: 'Image loaded sync', + file: 'test/test_img.png' +} + +p.send(msg, function (err, result, res) { + console.log('error', err) + console.log('result', result) + console.log('res.headers', res.headers) + // process.exit(0); +}) From 692dbfded8b92c22a1ddfce2621085a11e4a906c Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Fri, 19 Oct 2018 17:04:00 -0600 Subject: [PATCH 2/7] add blocking and non-blocking examples --- README.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/README.md b/README.md index 017a253..4be3510 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,81 @@ p.send( msg, function( err, result ) { }) ``` +### Sending a message with an attachment (blocking) +```javascript + +var Push = require( 'pushover-notifications' ) + +var p = new Push( { + user: process.env['PUSHOVER_USER'], + token: process.env['PUSHOVER_TOKEN'], + // httpOptions: { + // proxy: process.env['http_proxy'], + //}, + // onerror: function(error) {}, + // update_sounds: true // update the list of sounds every day - will + // prevent app from exiting. +}) + +var msg = { + // These values correspond to the parameters detailed on https://pushover.net/api + // 'message' is required. All other values are optional. + message: 'omg node test', // required + title: "Well - this is fantastic", + sound: 'magic', + device: 'devicename', + priority: 1, + file: '/tmp/fantastic.png' // this will read using fs.readFileSync()! +} + +p.send( msg, function( err, result ) { + if ( err ) { + throw err + } + + console.log( result ) +}) +``` + +### Sending a message with an attachment (non-blocking) +```javascript + +var Push = require( 'pushover-notifications' ) +var fs = require( 'fs' ) + +var p = new Push( { + user: process.env['PUSHOVER_USER'], + token: process.env['PUSHOVER_TOKEN'], + // httpOptions: { + // proxy: process.env['http_proxy'], + //}, + // onerror: function(error) {}, + // update_sounds: true // update the list of sounds every day - will + // prevent app from exiting. +}) + +fs.readFile('/tmp/fantastic.png', function(err, data) { + var msg = { + // These values correspond to the parameters detailed on https://pushover.net/api + // 'message' is required. All other values are optional. + message: 'omg node test', // required + title: "Well - this is fantastic", + sound: 'magic', + device: 'devicename', + priority: 1, + file: { name: 'fantastic.png', data: data } + } + + p.send( msg, function( err, result ) { + if ( err ) { + throw err + } + + console.log( result ) + }) +}) +``` + ### Sending a message to multiple users ```javascript From e87136e58bfc63f41b9cbf7d0e14b71ec18fb46f Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Fri, 19 Oct 2018 17:20:27 -0600 Subject: [PATCH 3/7] add missing image for tests --- test/test_img.png | Bin 0 -> 2698 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/test_img.png diff --git a/test/test_img.png b/test/test_img.png new file mode 100644 index 0000000000000000000000000000000000000000..f853575dca908308b7ba74f4257fc1f8afba2e5e GIT binary patch literal 2698 zcmV;53U&2~P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 Date: Sat, 20 Oct 2018 13:14:35 -0600 Subject: [PATCH 4/7] clean up test output, actually check error --- test/test-onerror.js | 3 --- test/test.js | 10 ++++++---- test/test_img.js | 19 ++++++++++--------- test/test_multi.js | 8 ++++---- test/test_proxy.js | 10 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/test/test-onerror.js b/test/test-onerror.js index b2e07cf..c0a7bfb 100644 --- a/test/test-onerror.js +++ b/test/test-onerror.js @@ -25,7 +25,4 @@ var msg = { } p.send(msg, function (err, result, res) { - console.log('error', err) - console.log('result', result) - console.log('res.headers', res.headers) }) diff --git a/test/test.js b/test/test.js index a97564f..49faa5e 100644 --- a/test/test.js +++ b/test/test.js @@ -16,8 +16,10 @@ var msg = { // console.log( p ); p.send(msg, function (err, result, res) { - console.log('error', err) - console.log('result', result) - console.log('res.headers', res.headers) - // process.exit(0); + console.log('====> Regular test') + if (err !== null) { + console.log(err) + process.exit(1) + } + process.exit(0); }) diff --git a/test/test_img.js b/test/test_img.js index e224ad8..56f165e 100644 --- a/test/test_img.js +++ b/test/test_img.js @@ -22,14 +22,14 @@ fs.readFile('test/test_img.png', function(err, data) { } p.send(msg, function (err, result, res) { - console.log('error', err) - console.log('result', result) - console.log('res.headers', res.headers) - // process.exit(0); + if (err !== null) { + console.log(err) + process.exit(1) + } + process.exit(0) }) }) -// console.log( p ); var msg = { message: 'test from ' + process.argv[1], sound: 'magic', @@ -38,8 +38,9 @@ var msg = { } p.send(msg, function (err, result, res) { - console.log('error', err) - console.log('result', result) - console.log('res.headers', res.headers) - // process.exit(0); + if (err !== null) { + console.log(err) + process.exit(1) + } + process.exit(0) }) diff --git a/test/test_multi.js b/test/test_multi.js index 1762770..b51bc6d 100644 --- a/test/test_multi.js +++ b/test/test_multi.js @@ -12,10 +12,10 @@ var msg = { user: process.env['PUSHOVER_USER'] } -// console.log( p ); - p.send(msg, function (err, result) { - console.log(err) - console.log(result) + if (err !== null) { + console.log(err) + process.exit(1) + } process.exit(0) }) diff --git a/test/test_proxy.js b/test/test_proxy.js index e70087e..cb5719e 100644 --- a/test/test_proxy.js +++ b/test/test_proxy.js @@ -16,10 +16,10 @@ var msg = { title: 'test from' } -// console.log( p ); - p.send(msg, function (err, result) { - console.log('error', err) - console.log('result', result) - // process.exit(0); + if (err !== null) { + console.log(err) + process.exit(1) + } + process.exit(0) }) From a949b59a77525f87ca8f658af67f2bb5ae13ba8b Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Sat, 20 Oct 2018 13:20:27 -0600 Subject: [PATCH 5/7] fix error check, label all the tests --- test/test-onerror.js | 1 + test/test.js | 6 ++---- test/test_img.js | 6 ++++-- test/test_multi.js | 3 ++- test/test_proxy.js | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/test/test-onerror.js b/test/test-onerror.js index c0a7bfb..b899ea2 100644 --- a/test/test-onerror.js +++ b/test/test-onerror.js @@ -25,4 +25,5 @@ var msg = { } p.send(msg, function (err, result, res) { + console.log('====> On error test') }) diff --git a/test/test.js b/test/test.js index 49faa5e..482e6ab 100644 --- a/test/test.js +++ b/test/test.js @@ -13,13 +13,11 @@ var msg = { title: 'Well - this is fantastic' } -// console.log( p ); - p.send(msg, function (err, result, res) { console.log('====> Regular test') - if (err !== null) { + if (err) { console.log(err) process.exit(1) } - process.exit(0); + process.exit(0) }) diff --git a/test/test_img.js b/test/test_img.js index 56f165e..0c701e9 100644 --- a/test/test_img.js +++ b/test/test_img.js @@ -22,7 +22,8 @@ fs.readFile('test/test_img.png', function(err, data) { } p.send(msg, function (err, result, res) { - if (err !== null) { + console.log('====> Async image test') + if (err) { console.log(err) process.exit(1) } @@ -38,7 +39,8 @@ var msg = { } p.send(msg, function (err, result, res) { - if (err !== null) { + console.log('====> Sync image test') + if (err) { console.log(err) process.exit(1) } diff --git a/test/test_multi.js b/test/test_multi.js index b51bc6d..1982160 100644 --- a/test/test_multi.js +++ b/test/test_multi.js @@ -13,7 +13,8 @@ var msg = { } p.send(msg, function (err, result) { - if (err !== null) { + console.log('====> Multi test') + if (err) { console.log(err) process.exit(1) } diff --git a/test/test_proxy.js b/test/test_proxy.js index cb5719e..56fce1a 100644 --- a/test/test_proxy.js +++ b/test/test_proxy.js @@ -17,7 +17,8 @@ var msg = { } p.send(msg, function (err, result) { - if (err !== null) { + console.log('====> Proxy test') + if (err) { console.log(err) process.exit(1) } From 9f13b3ebafbc7631c00d3f5013b4b6ffca86a408 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Mon, 22 Oct 2018 16:21:57 -0600 Subject: [PATCH 6/7] use .from to create image data buffer --- lib/pushover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pushover.js b/lib/pushover.js index 4ed9a73..e3721a9 100644 --- a/lib/pushover.js +++ b/lib/pushover.js @@ -69,7 +69,7 @@ function reqString2MP(rs, b, imgObj) { if (imgObj) { payload = Buffer.concat([ Buffer.from(a.join('\r\n'), 'utf8'), - new Buffer(imgObj.data, 'binary'), + Buffer.from(imgObj.data, 'binary'), Buffer.from('\r\n' + b + '--\r\n', 'utf8') ]) } else { From 77e4841f2aec6c7878dcfcba89f63dc02ca35911 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Mon, 22 Oct 2018 16:22:29 -0600 Subject: [PATCH 7/7] put creation of Push object in callback to avoid async issues --- README.md | 22 +++++++++++----------- test/test_img.js | 43 +++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 4be3510..d6521cf 100644 --- a/README.md +++ b/README.md @@ -107,18 +107,18 @@ p.send( msg, function( err, result ) { var Push = require( 'pushover-notifications' ) var fs = require( 'fs' ) -var p = new Push( { - user: process.env['PUSHOVER_USER'], - token: process.env['PUSHOVER_TOKEN'], - // httpOptions: { - // proxy: process.env['http_proxy'], - //}, - // onerror: function(error) {}, - // update_sounds: true // update the list of sounds every day - will - // prevent app from exiting. -}) - fs.readFile('/tmp/fantastic.png', function(err, data) { + var p = new Push( { + user: process.env['PUSHOVER_USER'], + token: process.env['PUSHOVER_TOKEN'], + // httpOptions: { + // proxy: process.env['http_proxy'], + //}, + // onerror: function(error) {}, + // update_sounds: true // update the list of sounds every day - will + // prevent app from exiting. + }) + var msg = { // These values correspond to the parameters detailed on https://pushover.net/api // 'message' is required. All other values are optional. diff --git a/test/test_img.js b/test/test_img.js index 0c701e9..29b6b1b 100644 --- a/test/test_img.js +++ b/test/test_img.js @@ -8,20 +8,43 @@ var p = new Push({ debug: true }) +var msg = { + message: 'test from ' + process.argv[1], + sound: 'magic', + title: 'Image loaded sync', + file: 'test/test_img.png' +} + +p.send(msg, function (err, result, res) { + console.log('====> Sync image test') + if (err) { + console.log(err) + process.exit(1) + } + process.exit(0) +}) + fs.readFile('test/test_img.png', function(err, data) { + var ap = new Push({ + user: process.env['PUSHOVER_USER'], + token: process.env['PUSHOVER_TOKEN'], + update_sounds: false, + debug: true + }) + var o = { name: 'pushover.png', data: data } - var msg = { + var amsg = { message: 'test from ' + process.argv[1], sound: 'magic', title: 'Image loaded async', file: o } - p.send(msg, function (err, result, res) { + ap.send(msg, function (err, result, res) { console.log('====> Async image test') if (err) { console.log(err) @@ -30,19 +53,3 @@ fs.readFile('test/test_img.png', function(err, data) { process.exit(0) }) }) - -var msg = { - message: 'test from ' + process.argv[1], - sound: 'magic', - title: 'Image loaded sync', - file: 'test/test_img.png' -} - -p.send(msg, function (err, result, res) { - console.log('====> Sync image test') - if (err) { - console.log(err) - process.exit(1) - } - process.exit(0) -})