UNPKG

4.06 kBJavaScriptView Raw
1/**
2 * Wrapper for the toaster (https://github.com/nels-o/toaster)
3 */
4var path = require('path');
5var notifier = path.resolve(__dirname, '../vendor/snoreToast/snoretoast');
6var utils = require('../lib/utils');
7var Balloon = require('./balloon');
8var os = require('os');
9const { v4: uuid } = require('uuid');
10
11var EventEmitter = require('events').EventEmitter;
12var util = require('util');
13
14var fallback;
15
16const PIPE_NAME = 'notifierPipe';
17const PIPE_PATH_PREFIX = '\\\\.\\pipe\\';
18
19module.exports = WindowsToaster;
20
21function WindowsToaster(options) {
22 options = utils.clone(options || {});
23 if (!(this instanceof WindowsToaster)) {
24 return new WindowsToaster(options);
25 }
26
27 this.options = options;
28
29 EventEmitter.call(this);
30}
31util.inherits(WindowsToaster, EventEmitter);
32
33function noop() {}
34
35function parseResult(data) {
36 if (!data) {
37 return {};
38 }
39 return data.split(';').reduce((acc, cur) => {
40 const split = cur.split('=');
41 if (split && split.length === 2) {
42 acc[split[0]] = split[1];
43 }
44 return acc;
45 }, {});
46}
47
48function getPipeName() {
49 return `${PIPE_PATH_PREFIX}${PIPE_NAME}-${uuid()}`;
50}
51
52function notifyRaw(options, callback) {
53 options = utils.clone(options || {});
54 callback = callback || noop;
55 var is64Bit = os.arch() === 'x64';
56 var resultBuffer;
57 const server = {
58 namedPipe: getPipeName()
59 };
60
61 if (typeof options === 'string') {
62 options = { title: 'node-notifier', message: options };
63 }
64
65 if (typeof callback !== 'function') {
66 throw new TypeError(
67 'The second argument must be a function callback. You have passed ' +
68 typeof fn
69 );
70 }
71
72 var snoreToastResultParser = (err, callback) => {
73 /* Possible exit statuses from SnoreToast, we only want to include err if it's -1 code
74 Exit Status : Exit Code
75 Failed : -1
76
77 Success : 0
78 Hidden : 1
79 Dismissed : 2
80 TimedOut : 3
81 ButtonPressed : 4
82 TextEntered : 5
83 */
84 const result = parseResult(
85 resultBuffer && resultBuffer.toString('utf16le')
86 );
87
88 // parse action
89 if (result.action === 'buttonClicked' && result.button) {
90 result.activationType = result.button;
91 } else if (result.action) {
92 result.activationType = result.action;
93 }
94
95 if (err && err.code === -1) {
96 callback(err, result);
97 }
98 callback(null, result);
99
100 // https://github.com/mikaelbr/node-notifier/issues/334
101 // Due to an issue with snoretoast not using stdio and pipe
102 // when notifications are disabled, make sure named pipe server
103 // is closed before exiting.
104 server.instance && server.instance.close();
105 };
106
107 var actionJackedCallback = (err) =>
108 snoreToastResultParser(
109 err,
110 utils.actionJackerDecorator(
111 this,
112 options,
113 callback,
114 (data) => data || false
115 )
116 );
117
118 options.title = options.title || 'Node Notification:';
119 if (
120 typeof options.message === 'undefined' &&
121 typeof options.close === 'undefined'
122 ) {
123 callback(new Error('Message or ID to close is required.'));
124 return this;
125 }
126
127 if (!utils.isWin8() && !utils.isWSL() && !!this.options.withFallback) {
128 fallback = fallback || new Balloon(this.options);
129 return fallback.notify(options, callback);
130 }
131
132 // Add pipeName option, to get the output
133 utils.createNamedPipe(server).then((out) => {
134 resultBuffer = out;
135 options.pipeName = server.namedPipe;
136
137 options = utils.mapToWin8(options);
138 var argsList = utils.constructArgumentList(options, {
139 explicitTrue: true,
140 wrapper: '',
141 keepNewlines: true,
142 noEscape: true
143 });
144
145 var notifierWithArch = notifier + '-x' + (is64Bit ? '64' : '86') + '.exe';
146 utils.fileCommand(
147 this.options.customPath || notifierWithArch,
148 argsList,
149 actionJackedCallback
150 );
151 });
152 return this;
153}
154
155Object.defineProperty(WindowsToaster.prototype, 'notify', {
156 get: function () {
157 if (!this._notify) this._notify = notifyRaw.bind(this);
158 return this._notify;
159 }
160});