diff --git a/host.js b/host.js new file mode 100755 index 0000000..85d1302 --- /dev/null +++ b/host.js @@ -0,0 +1,69 @@ +'use strict'; + +var spawn = require('child_process').spawn; + +var config = { + version: '0.1.0', + isWin: /^win/.test(process.platform) +}; + +function observe (msg, push, done) { + if (msg.cmd === 'version') { + push({ + version: config.version + }); + done(); + } + else if (msg.cmd === 'echo') { + push(msg); + done(); + } + else if (msg.cmd === 'spawn') { + let sp = spawn(msg.command, msg.arguments); + sp.stdout.on('data', stdout => push({stdout})); + sp.stderr.on('data', stderr => push({stderr})); + sp.on('close', (code) => { + push({code}); + done(); + }); + } + else if (msg.cmd === 'exec') { + let sp = spawn(msg.command, msg.arguments); + let stderr = '', stdout = ''; + sp.stdout.on('data', data => stdout += data); + sp.stderr.on('data', data => stderr += data); + sp.on('close', (code) => { + push({ + code, + stderr, + stdout + }); + done(); + }); + } + else if (msg.cmd === 'env') { + push({ + env: process.env + }); + done(); + } + else { + push({ + error: 'cmd is unknown', + cmd: msg.cmd + }); + done(); + } +} +/* message passing */ +var nativeMessage = require('./messaging'); + +var input = new nativeMessage.Input(); +var transform = new nativeMessage.Transform(observe); +var output = new nativeMessage.Output(); + +process.stdin + .pipe(input) + .pipe(transform) + .pipe(output) + .pipe(process.stdout); diff --git a/install-linux.js b/install-linux.js new file mode 100644 index 0000000..34ae29d --- /dev/null +++ b/install-linux.js @@ -0,0 +1,119 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); + +function exists (directory, callback) { + let root = '/'; + let dirs = directory.split('/'); + function one () { + root = path.join(root, dirs.shift()); + fs.stat(root, (e) => { + if (!e && dirs.length) { + one(); + } + else if (e && e.code === 'ENOENT') { + fs.mkdir(root, (e) => { + if (e) { + callback(e); + } + else if (dirs.length) { + one(); + } + else { + callback(); + } + }); + } + else { + callback(e); + } + }); + } + one(); +} + +var dir = path.join('/usr/share', 'com.add0n.node'); +var name = 'com.add0n.node'; +var ids = { + chrome: [ + 'lmeddoobegbaiopohmpmmobpnpjifpii', // open in Firefox (Chrome) + 'agaecbnjediafcdopcfidcdiponjlmnk', // open in Explorer (Chrome) + ], + firefox: [ + '{5610edea-88c1-4370-b93d-86aa131971d1}', // open in Explorer + ] +}; +function manifest (root, type, callback) { + exists(root, (e) => { + if (e) { + throw e; + } + let origins; + if (type === 'chrome') { + origins = '"allowed_origins": ' + JSON.stringify(ids.chrome.map(id => 'chrome-extension://' + id + '/')); + } + else { + origins = '"allowed_extensions": ' + JSON.stringify(ids.firefox); + } + fs.writeFile(path.join(root, name + '.json'), `{ + "name": "${name}", + "description": "Node Host for Native Messaging", + "path": "${path.join(dir, 'run.sh')}", + "type": "stdio", + ${origins} + }`, (e) => { + if (e) { + throw e; + } + callback(); + }); + + }); +} +function application (callback) { + exists(dir, (e) => { + if (e) { + throw e; + } + let isNode = process.argv[2] !== '--add_node'; + let run = isNode ? `#!/bin/bash\n${process.argv[2]} host.js` : '#!/bin/bash\n./node host.js'; + fs.writeFile(path.join(dir, 'run.sh'), run, (e) => { + if (e) { + throw e; + } + fs.chmodSync(path.join(dir, 'run.sh'), '0755'); + if (!isNode) { + fs.createReadStream('../node').pipe(fs.createWriteStream(path.join(dir, 'node'))); + fs.chmodSync(path.join(dir, 'node'), '0755'); + } + fs.createReadStream('host.js').pipe(fs.createWriteStream(path.join(dir, 'host.js'))); + fs.createReadStream('messaging.js').pipe(fs.createWriteStream(path.join(dir, 'messaging.js'))); + callback(); + }); + }); +} +function chrome (callback) { + if (ids.chrome.length) { + manifest('/etc/opt/chrome/native-messaging-hosts', 'chrome', callback); + console.error('Chrome Browser is supported'); + } + else { + callback(); + } +} +function firefox (callback) { + if (ids.firefox.length) { + manifest('/usr/lib/mozilla/native-messaging-hosts', 'firefox', callback); + console.error('Firefox Browser is supported'); + } + else { + callback(); + } +} +chrome(() => firefox(() => { + application(() => { + console.error('Native Host is installed in', dir); + console.error('>> Application is ready to use <<'); + }); +})); diff --git a/install-windows.js b/install-windows.js new file mode 100644 index 0000000..27dc331 --- /dev/null +++ b/install-windows.js @@ -0,0 +1,91 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); + +function exists (directory, callback) { + fs.stat(directory, (e) => { + + if (e && e.code === 'ENOENT') { + fs.mkdir(directory, callback); + } + else { + callback(e); + } + }); +} + +var dir = path.join(process.argv[2], 'com.add0n.node'); +var name = 'com.add0n.node'; +var ids = { + chrome: [ + 'lmeddoobegbaiopohmpmmobpnpjifpii', // open in Firefox (Chrome) + 'agaecbnjediafcdopcfidcdiponjlmnk', // open in Explorer (Chrome) + ], + firefox: [ + '{5610edea-88c1-4370-b93d-86aa131971d1}', // open in Explorer + ] +}; + +function manifest (type, callback) { + exists(dir, (e) => { + if (e) { + throw e; + } + let origins; + if (type === 'chrome') { + origins = '"allowed_origins": ' + JSON.stringify(ids.chrome.map(id => 'chrome-extension://' + id + '/')); + } + else { + origins = '"allowed_extensions": ' + JSON.stringify(ids.firefox); + } + fs.writeFile(path.join(dir, 'manifest-' + type + '.json'), `{ + "name": "${name}", + "description": "Node Host for Native Messaging", + "path": "run.bat", + "type": "stdio", + ${origins} +}`, (e) => { + if (e) { + throw e; + } + callback(); + }); + }); +} +function application (callback) { + fs.writeFile(path.join(dir, 'run.bat'), `@echo off\n\n"%~dp0node.exe" "%~dp0host.js"`, (e) => { + if (e) { + throw e; + } + fs.createReadStream('..\\node.exe').pipe(fs.createWriteStream(path.join(dir, 'node.exe'))); + fs.createReadStream('host.js').pipe(fs.createWriteStream(path.join(dir, 'host.js'))); + fs.createReadStream('messaging.js').pipe(fs.createWriteStream(path.join(dir, 'messaging.js'))); + callback(); + }); +} + +function chrome (callback) { + if (ids.chrome.length) { + manifest('chrome', callback); + console.error('Chrome Browser is supported'); + } + else { + callback(); + } +} +function firefox (callback) { + if (ids.firefox.length) { + manifest('firefox', callback); + console.error('Firefox Browser is supported'); + } + else { + callback(); + } +} +chrome(() => firefox(() => { + application(() => { + console.error('Native Host is installed in', dir); + console.error('>> Application is ready to use <<'); + }); +})); diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..bee374a --- /dev/null +++ b/install.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +cd ./app + +if type node 2>/dev/null; then + echo Installer is using your system node.js + sudo node install.js `which node` +else + echo Installer is using the attached node.js + sudo ../node install.js --add_node +fi + diff --git a/linux/app/host.js b/linux/app/host.js deleted file mode 100755 index 85d1302..0000000 --- a/linux/app/host.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -var spawn = require('child_process').spawn; - -var config = { - version: '0.1.0', - isWin: /^win/.test(process.platform) -}; - -function observe (msg, push, done) { - if (msg.cmd === 'version') { - push({ - version: config.version - }); - done(); - } - else if (msg.cmd === 'echo') { - push(msg); - done(); - } - else if (msg.cmd === 'spawn') { - let sp = spawn(msg.command, msg.arguments); - sp.stdout.on('data', stdout => push({stdout})); - sp.stderr.on('data', stderr => push({stderr})); - sp.on('close', (code) => { - push({code}); - done(); - }); - } - else if (msg.cmd === 'exec') { - let sp = spawn(msg.command, msg.arguments); - let stderr = '', stdout = ''; - sp.stdout.on('data', data => stdout += data); - sp.stderr.on('data', data => stderr += data); - sp.on('close', (code) => { - push({ - code, - stderr, - stdout - }); - done(); - }); - } - else if (msg.cmd === 'env') { - push({ - env: process.env - }); - done(); - } - else { - push({ - error: 'cmd is unknown', - cmd: msg.cmd - }); - done(); - } -} -/* message passing */ -var nativeMessage = require('./messaging'); - -var input = new nativeMessage.Input(); -var transform = new nativeMessage.Transform(observe); -var output = new nativeMessage.Output(); - -process.stdin - .pipe(input) - .pipe(transform) - .pipe(output) - .pipe(process.stdout); diff --git a/linux/app/host.js b/linux/app/host.js new file mode 120000 index 0000000..ae42609 --- /dev/null +++ b/linux/app/host.js @@ -0,0 +1 @@ +../../host.js \ No newline at end of file diff --git a/linux/app/install.js b/linux/app/install.js deleted file mode 100644 index 78fa42f..0000000 --- a/linux/app/install.js +++ /dev/null @@ -1,115 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); - -function exists (directory, callback) { - let root = '/'; - let dirs = directory.split('/'); - function one () { - root = path.join(root, dirs.shift()); - fs.stat(root, (e) => { - if (!e && dirs.length) { - one(); - } - else if (e && e.code === 'ENOENT') { - fs.mkdir(root, (e) => { - if (e) { - callback(e); - } - else if (dirs.length) { - one(); - } - else { - callback(); - } - }); - } - else { - callback(e); - } - }); - } - one(); -} - -var dir = path.join('/usr/share', 'com.add0n.node'); -var name = 'com.add0n.node'; -var ids = { - chrome: ['lmeddoobegbaiopohmpmmobpnpjifpii'], - firefox: [] -}; - -function manifest (root, type, callback) { - exists(root, (e) => { - if (e) { - throw e; - } - let origins; - if (type === 'chrome') { - origins = '"allowed_origins": ' + JSON.stringify(ids.chrome.map(id => 'chrome-extension://' + id + '/')); - } - else { - origins = '"allowed_extensions": ' + JSON.stringify(ids.firefox); - } - fs.writeFile(path.join(root, name + '.json'), `{ - "name": "${name}", - "description": "Node Host for Native Messaging", - "path": "${path.join(dir, 'run.sh')}", - "type": "stdio", - ${origins} - }`, (e) => { - if (e) { - throw e; - } - callback(); - }); - - }); -} -function application (callback) { - exists(dir, (e) => { - if (e) { - throw e; - } - let isNode = process.argv[2] !== '--add_node'; - let run = isNode ? `#!/bin/bash\n${process.argv[2]} host.js` : '#!/bin/bash\n./node host.js'; - fs.writeFile(path.join(dir, 'run.sh'), run, (e) => { - if (e) { - throw e; - } - fs.chmodSync(path.join(dir, 'run.sh'), '0755'); - if (!isNode) { - fs.createReadStream('../node').pipe(fs.createWriteStream(path.join(dir, 'node'))); - fs.chmodSync(path.join(dir, 'node'), '0755'); - } - fs.createReadStream('host.js').pipe(fs.createWriteStream(path.join(dir, 'host.js'))); - fs.createReadStream('messaging.js').pipe(fs.createWriteStream(path.join(dir, 'messaging.js'))); - callback(); - }); - }); -} -function chrome (callback) { - if (ids.chrome.length) { - manifest('/etc/opt/chrome/native-messaging-hosts', 'chrome', callback); - console.error('Chrome Browser is supported'); - } - else { - callback(); - } -} -function firefox (callback) { - if (ids.firefox.length) { - manifest('/usr/lib/mozilla/native-messaging-hosts', 'firefox', callback); - console.error('Firefox Browser is supported'); - } - else { - callback(); - } -} -chrome(() => firefox(() => { - application(() => { - console.error('Native Host is installed in', dir); - console.error('>> Application is ready to use <<'); - }); -})); diff --git a/linux/app/install.js b/linux/app/install.js new file mode 120000 index 0000000..4af030f --- /dev/null +++ b/linux/app/install.js @@ -0,0 +1 @@ +../../install-linux.js \ No newline at end of file diff --git a/linux/app/messaging.js b/linux/app/messaging.js deleted file mode 100644 index d62ec9c..0000000 --- a/linux/app/messaging.js +++ /dev/null @@ -1,128 +0,0 @@ -// chrome-native-messaging module -// -// Defines three Transform streams: -// -// - Input - transform native messages to JavaScript objects -// - Output - transform JavaScript objects to native messages -// - Transform - transform message objects to reply objects -// - Debug - transform JavaScript objects to lines of JSON (for debugging, obviously) - -var stream = require('stream'); -var util = require('util'); - -function Input() { - stream.Transform.call(this); - - // Transform bytes... - this._writableState.objectMode = false; - // ...into objects. - this._readableState.objectMode = true; - - // Unparsed data. - this.buf = new Buffer(0); - // Parsed length. - this.len = null; -} - -util.inherits(Input, stream.Transform); - -Input.prototype._transform = function(chunk, encoding, done) { - // Save this chunk. - this.buf = Buffer.concat([ this.buf, chunk ]); - - var self = this; - - function parseBuf() { - // Do we have a length yet? - if (typeof self.len !== 'number') { - // Nope. Do we have enough bytes for the length? - if (self.buf.length >= 4) { - // Yep. Parse the bytes. - self.len = self.buf.readUInt32LE(0); - // Remove the length bytes from the buffer. - self.buf = self.buf.slice(4); - } - } - - // Do we have a length yet? (We may have just parsed it.) - if (typeof self.len === 'number') { - // Yep. Do we have enough bytes for the message? - if (self.buf.length >= self.len) { - // Yep. Slice off the bytes we need. - var message = self.buf.slice(0, self.len); - // Remove the bytes for the message from the buffer. - self.buf = self.buf.slice(self.len); - // Clear the length so we know we need to parse it again. - self.len = null; - // Parse the message bytes. - var obj = JSON.parse(message.toString()); - // Enqueue it for reading. - self.push(obj); - // We could have more messages in the buffer so check again. - parseBuf(); - } - } - } - - // Check for a parsable buffer (both length and message). - parseBuf(); - - // We're done. - done(); -}; - -function Output() { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = false; -} - -util.inherits(Output, stream.Transform); - -Output.prototype._transform = function(chunk, encoding, done) { - var len = new Buffer(4); - var buf = new Buffer(JSON.stringify(chunk)); - - len.writeUInt32LE(buf.length, 0); - - this.push(len); - this.push(buf); - - done(); -}; - -function Transform(handler) { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = true; - - this.handler = handler; -} - -util.inherits(Transform, stream.Transform); - -Transform.prototype._transform = function(msg, encoding, done) { - this.handler(msg, this.push.bind(this), done); -}; - -function Debug() { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = false; -} - -util.inherits(Debug, stream.Transform); - -Debug.prototype._transform = function(chunk, encoding, done) { - this.push(JSON.stringify(chunk) + '\n'); - - done(); -}; - -exports.Input = Input; -exports.Output = Output; -exports.Transform = Transform; -exports.Debug = Debug; diff --git a/linux/app/messaging.js b/linux/app/messaging.js new file mode 120000 index 0000000..ee7b302 --- /dev/null +++ b/linux/app/messaging.js @@ -0,0 +1 @@ +../../messaging.js \ No newline at end of file diff --git a/linux/install.sh b/linux/install.sh deleted file mode 100755 index bee374a..0000000 --- a/linux/install.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -cd ./app - -if type node 2>/dev/null; then - echo Installer is using your system node.js - sudo node install.js `which node` -else - echo Installer is using the attached node.js - sudo ../node install.js --add_node -fi - diff --git a/linux/install.sh b/linux/install.sh new file mode 120000 index 0000000..3f44f99 --- /dev/null +++ b/linux/install.sh @@ -0,0 +1 @@ +../install.sh \ No newline at end of file diff --git a/mac/app/host.js b/mac/app/host.js deleted file mode 100755 index 85d1302..0000000 --- a/mac/app/host.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -var spawn = require('child_process').spawn; - -var config = { - version: '0.1.0', - isWin: /^win/.test(process.platform) -}; - -function observe (msg, push, done) { - if (msg.cmd === 'version') { - push({ - version: config.version - }); - done(); - } - else if (msg.cmd === 'echo') { - push(msg); - done(); - } - else if (msg.cmd === 'spawn') { - let sp = spawn(msg.command, msg.arguments); - sp.stdout.on('data', stdout => push({stdout})); - sp.stderr.on('data', stderr => push({stderr})); - sp.on('close', (code) => { - push({code}); - done(); - }); - } - else if (msg.cmd === 'exec') { - let sp = spawn(msg.command, msg.arguments); - let stderr = '', stdout = ''; - sp.stdout.on('data', data => stdout += data); - sp.stderr.on('data', data => stderr += data); - sp.on('close', (code) => { - push({ - code, - stderr, - stdout - }); - done(); - }); - } - else if (msg.cmd === 'env') { - push({ - env: process.env - }); - done(); - } - else { - push({ - error: 'cmd is unknown', - cmd: msg.cmd - }); - done(); - } -} -/* message passing */ -var nativeMessage = require('./messaging'); - -var input = new nativeMessage.Input(); -var transform = new nativeMessage.Transform(observe); -var output = new nativeMessage.Output(); - -process.stdin - .pipe(input) - .pipe(transform) - .pipe(output) - .pipe(process.stdout); diff --git a/mac/app/host.js b/mac/app/host.js new file mode 120000 index 0000000..ae42609 --- /dev/null +++ b/mac/app/host.js @@ -0,0 +1 @@ +../../host.js \ No newline at end of file diff --git a/mac/app/install.js b/mac/app/install.js deleted file mode 100644 index 4da7ef6..0000000 --- a/mac/app/install.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); - -function exists (directory, callback) { - let root = '/'; - let dirs = directory.split('/'); - function one () { - root = path.join(root, dirs.shift()); - fs.stat(root, (e) => { - if (!e && dirs.length) { - one(); - } - else if (e && e.code === 'ENOENT') { - fs.mkdir(root, (e) => { - if (e) { - callback(e); - } - else if (dirs.length) { - one(); - } - else { - callback(); - } - }); - } - else { - callback(e); - } - }); - } - one(); -} - -var dir = path.join('/usr/share', 'com.add0n.node'); -var name = 'com.add0n.node'; -var ids = { - chrome: [ - 'lmeddoobegbaiopohmpmmobpnpjifpii' // open in Firefox (Chrome) - ], - firefox: [] -}; - -function manifest (root, type, callback) { - exists(root, (e) => { - if (e) { - throw e; - } - - let origins; - if (type === 'chrome') { - origins = '"allowed_origins": ' + JSON.stringify(ids.chrome.map(id => 'chrome-extension://' + id + '/')); - } - else { - origins = '"allowed_extensions": ' + JSON.stringify(ids.firefox); - } - fs.writeFile(path.join(root, name + '.json'), `{ - "name": "${name}", - "description": "Node Host for Native Messaging", - "path": "${path.join(dir, 'run.sh')}", - "type": "stdio", - ${origins} -}`, (e) => { - if (e) { - throw e; - } - callback(); - }); - - }); -} - -console.error(process.argv) - -function application (callback) { - exists(dir, (e) => { - if (e) { - throw e; - } - - let isNode = process.argv[2] !== '--add_node'; - let run = isNode ? `#!/bin/bash\n${process.argv[2]} host.js` : '#!/bin/bash\n./node host.js'; - fs.writeFile(path.join(dir, 'run.sh'), run, (e) => { - if (e) { - throw e; - } - fs.chmodSync(path.join(dir, 'run.sh'), '0755'); - if (!isNode) { - fs.createReadStream('../node').pipe(fs.createWriteStream(path.join(dir, 'node'))); - fs.chmodSync(path.join(dir, 'node'), '0755'); - } - fs.createReadStream('host.js').pipe(fs.createWriteStream(path.join(dir, 'host.js'))); - fs.createReadStream('messaging.js').pipe(fs.createWriteStream(path.join(dir, 'messaging.js'))); - callback(); - }); - }); -} - -function chrome (callback) { - if (ids.chrome.length) { - manifest('/Library/Google/Chrome/NativeMessagingHosts', 'chrome', callback); - console.error('Chrome Browser is supported'); - } - else { - callback(); - } -} -function firefox (callback) { - if (ids.firefox.length) { - manifest('/Library/Application Support/Mozilla/NativeMessagingHosts', 'firefox', callback); - console.error('Firefox Browser is supported'); - } - else { - callback(); - } -} -chrome(() => firefox(() => { - application(() => { - console.error('Native Host is installed in', dir); - console.error('>> Application is ready to use <<'); - }); -})); diff --git a/mac/app/install.js b/mac/app/install.js new file mode 120000 index 0000000..4af030f --- /dev/null +++ b/mac/app/install.js @@ -0,0 +1 @@ +../../install-linux.js \ No newline at end of file diff --git a/mac/app/messaging.js b/mac/app/messaging.js deleted file mode 100644 index d62ec9c..0000000 --- a/mac/app/messaging.js +++ /dev/null @@ -1,128 +0,0 @@ -// chrome-native-messaging module -// -// Defines three Transform streams: -// -// - Input - transform native messages to JavaScript objects -// - Output - transform JavaScript objects to native messages -// - Transform - transform message objects to reply objects -// - Debug - transform JavaScript objects to lines of JSON (for debugging, obviously) - -var stream = require('stream'); -var util = require('util'); - -function Input() { - stream.Transform.call(this); - - // Transform bytes... - this._writableState.objectMode = false; - // ...into objects. - this._readableState.objectMode = true; - - // Unparsed data. - this.buf = new Buffer(0); - // Parsed length. - this.len = null; -} - -util.inherits(Input, stream.Transform); - -Input.prototype._transform = function(chunk, encoding, done) { - // Save this chunk. - this.buf = Buffer.concat([ this.buf, chunk ]); - - var self = this; - - function parseBuf() { - // Do we have a length yet? - if (typeof self.len !== 'number') { - // Nope. Do we have enough bytes for the length? - if (self.buf.length >= 4) { - // Yep. Parse the bytes. - self.len = self.buf.readUInt32LE(0); - // Remove the length bytes from the buffer. - self.buf = self.buf.slice(4); - } - } - - // Do we have a length yet? (We may have just parsed it.) - if (typeof self.len === 'number') { - // Yep. Do we have enough bytes for the message? - if (self.buf.length >= self.len) { - // Yep. Slice off the bytes we need. - var message = self.buf.slice(0, self.len); - // Remove the bytes for the message from the buffer. - self.buf = self.buf.slice(self.len); - // Clear the length so we know we need to parse it again. - self.len = null; - // Parse the message bytes. - var obj = JSON.parse(message.toString()); - // Enqueue it for reading. - self.push(obj); - // We could have more messages in the buffer so check again. - parseBuf(); - } - } - } - - // Check for a parsable buffer (both length and message). - parseBuf(); - - // We're done. - done(); -}; - -function Output() { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = false; -} - -util.inherits(Output, stream.Transform); - -Output.prototype._transform = function(chunk, encoding, done) { - var len = new Buffer(4); - var buf = new Buffer(JSON.stringify(chunk)); - - len.writeUInt32LE(buf.length, 0); - - this.push(len); - this.push(buf); - - done(); -}; - -function Transform(handler) { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = true; - - this.handler = handler; -} - -util.inherits(Transform, stream.Transform); - -Transform.prototype._transform = function(msg, encoding, done) { - this.handler(msg, this.push.bind(this), done); -}; - -function Debug() { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = false; -} - -util.inherits(Debug, stream.Transform); - -Debug.prototype._transform = function(chunk, encoding, done) { - this.push(JSON.stringify(chunk) + '\n'); - - done(); -}; - -exports.Input = Input; -exports.Output = Output; -exports.Transform = Transform; -exports.Debug = Debug; diff --git a/mac/app/messaging.js b/mac/app/messaging.js new file mode 120000 index 0000000..ee7b302 --- /dev/null +++ b/mac/app/messaging.js @@ -0,0 +1 @@ +../../messaging.js \ No newline at end of file diff --git a/mac/install.sh b/mac/install.sh deleted file mode 100755 index bee374a..0000000 --- a/mac/install.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -cd ./app - -if type node 2>/dev/null; then - echo Installer is using your system node.js - sudo node install.js `which node` -else - echo Installer is using the attached node.js - sudo ../node install.js --add_node -fi - diff --git a/mac/install.sh b/mac/install.sh new file mode 120000 index 0000000..3f44f99 --- /dev/null +++ b/mac/install.sh @@ -0,0 +1 @@ +../install.sh \ No newline at end of file diff --git a/messaging.js b/messaging.js new file mode 100644 index 0000000..d62ec9c --- /dev/null +++ b/messaging.js @@ -0,0 +1,128 @@ +// chrome-native-messaging module +// +// Defines three Transform streams: +// +// - Input - transform native messages to JavaScript objects +// - Output - transform JavaScript objects to native messages +// - Transform - transform message objects to reply objects +// - Debug - transform JavaScript objects to lines of JSON (for debugging, obviously) + +var stream = require('stream'); +var util = require('util'); + +function Input() { + stream.Transform.call(this); + + // Transform bytes... + this._writableState.objectMode = false; + // ...into objects. + this._readableState.objectMode = true; + + // Unparsed data. + this.buf = new Buffer(0); + // Parsed length. + this.len = null; +} + +util.inherits(Input, stream.Transform); + +Input.prototype._transform = function(chunk, encoding, done) { + // Save this chunk. + this.buf = Buffer.concat([ this.buf, chunk ]); + + var self = this; + + function parseBuf() { + // Do we have a length yet? + if (typeof self.len !== 'number') { + // Nope. Do we have enough bytes for the length? + if (self.buf.length >= 4) { + // Yep. Parse the bytes. + self.len = self.buf.readUInt32LE(0); + // Remove the length bytes from the buffer. + self.buf = self.buf.slice(4); + } + } + + // Do we have a length yet? (We may have just parsed it.) + if (typeof self.len === 'number') { + // Yep. Do we have enough bytes for the message? + if (self.buf.length >= self.len) { + // Yep. Slice off the bytes we need. + var message = self.buf.slice(0, self.len); + // Remove the bytes for the message from the buffer. + self.buf = self.buf.slice(self.len); + // Clear the length so we know we need to parse it again. + self.len = null; + // Parse the message bytes. + var obj = JSON.parse(message.toString()); + // Enqueue it for reading. + self.push(obj); + // We could have more messages in the buffer so check again. + parseBuf(); + } + } + } + + // Check for a parsable buffer (both length and message). + parseBuf(); + + // We're done. + done(); +}; + +function Output() { + stream.Transform.call(this); + + this._writableState.objectMode = true; + this._readableState.objectMode = false; +} + +util.inherits(Output, stream.Transform); + +Output.prototype._transform = function(chunk, encoding, done) { + var len = new Buffer(4); + var buf = new Buffer(JSON.stringify(chunk)); + + len.writeUInt32LE(buf.length, 0); + + this.push(len); + this.push(buf); + + done(); +}; + +function Transform(handler) { + stream.Transform.call(this); + + this._writableState.objectMode = true; + this._readableState.objectMode = true; + + this.handler = handler; +} + +util.inherits(Transform, stream.Transform); + +Transform.prototype._transform = function(msg, encoding, done) { + this.handler(msg, this.push.bind(this), done); +}; + +function Debug() { + stream.Transform.call(this); + + this._writableState.objectMode = true; + this._readableState.objectMode = false; +} + +util.inherits(Debug, stream.Transform); + +Debug.prototype._transform = function(chunk, encoding, done) { + this.push(JSON.stringify(chunk) + '\n'); + + done(); +}; + +exports.Input = Input; +exports.Output = Output; +exports.Transform = Transform; +exports.Debug = Debug; diff --git a/prepare.sh b/prepare.sh new file mode 100755 index 0000000..6c4cd7b --- /dev/null +++ b/prepare.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd linux +zip ../linux.zip -9 -r * -x "*.DS_Store" +cd ../mac +zip ../mac.zip -9 -r * -x "*.DS_Store" +cd ../windows +zip ../windows.zip -9 -r * -x "*.DS_Store" diff --git a/windows/app/host.js b/windows/app/host.js deleted file mode 100755 index 85d1302..0000000 --- a/windows/app/host.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -var spawn = require('child_process').spawn; - -var config = { - version: '0.1.0', - isWin: /^win/.test(process.platform) -}; - -function observe (msg, push, done) { - if (msg.cmd === 'version') { - push({ - version: config.version - }); - done(); - } - else if (msg.cmd === 'echo') { - push(msg); - done(); - } - else if (msg.cmd === 'spawn') { - let sp = spawn(msg.command, msg.arguments); - sp.stdout.on('data', stdout => push({stdout})); - sp.stderr.on('data', stderr => push({stderr})); - sp.on('close', (code) => { - push({code}); - done(); - }); - } - else if (msg.cmd === 'exec') { - let sp = spawn(msg.command, msg.arguments); - let stderr = '', stdout = ''; - sp.stdout.on('data', data => stdout += data); - sp.stderr.on('data', data => stderr += data); - sp.on('close', (code) => { - push({ - code, - stderr, - stdout - }); - done(); - }); - } - else if (msg.cmd === 'env') { - push({ - env: process.env - }); - done(); - } - else { - push({ - error: 'cmd is unknown', - cmd: msg.cmd - }); - done(); - } -} -/* message passing */ -var nativeMessage = require('./messaging'); - -var input = new nativeMessage.Input(); -var transform = new nativeMessage.Transform(observe); -var output = new nativeMessage.Output(); - -process.stdin - .pipe(input) - .pipe(transform) - .pipe(output) - .pipe(process.stdout); diff --git a/windows/app/host.js b/windows/app/host.js new file mode 120000 index 0000000..ae42609 --- /dev/null +++ b/windows/app/host.js @@ -0,0 +1 @@ +../../host.js \ No newline at end of file diff --git a/windows/app/install.js b/windows/app/install.js deleted file mode 100644 index bd743d1..0000000 --- a/windows/app/install.js +++ /dev/null @@ -1,88 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); - -function exists (directory, callback) { - fs.stat(directory, (e) => { - - if (e && e.code === 'ENOENT') { - fs.mkdir(directory, callback); - } - else { - callback(e); - } - }); -} - -var dir = path.join(process.argv[2], 'com.add0n.node'); -var name = 'com.add0n.node'; -var ids = { - chrome: [ - 'lmeddoobegbaiopohmpmmobpnpjifpii' // open in Firefox (Chrome) - ], - firefox: [] -}; - -function manifest (type, callback) { - exists(dir, (e) => { - if (e) { - throw e; - } - let origins; - if (type === 'chrome') { - origins = '"allowed_origins": ' + JSON.stringify(ids.chrome.map(id => 'chrome-extension://' + id + '/')); - } - else { - origins = '"allowed_extensions": ' + JSON.stringify(ids.firefox); - } - fs.writeFile(path.join(dir, 'manifest-' + type + '.json'), `{ - "name": "${name}", - "description": "Node Host for Native Messaging", - "path": "run.bat", - "type": "stdio", - ${origins} -}`, (e) => { - if (e) { - throw e; - } - callback(); - }); - }); -} -function application (callback) { - fs.writeFile(path.join(dir, 'run.bat'), `@echo off\n\n"%~dp0node.exe" "%~dp0host.js"`, (e) => { - if (e) { - throw e; - } - fs.createReadStream('..\\node.exe').pipe(fs.createWriteStream(path.join(dir, 'node.exe'))); - fs.createReadStream('host.js').pipe(fs.createWriteStream(path.join(dir, 'host.js'))); - fs.createReadStream('messaging.js').pipe(fs.createWriteStream(path.join(dir, 'messaging.js'))); - callback(); - }); -} - -function chrome (callback) { - if (ids.chrome.length) { - manifest('chrome', callback); - console.error('Chrome Browser is supported'); - } - else { - callback(); - } -} -function firefox (callback) { - if (ids.firefox.length) { - manifest('firefox', callback); - console.error('Firefox Browser is supported'); - } - else { - callback(); - } -} -chrome(() => firefox(() => { - application(() => { - console.error('Native Host is installed in', dir); - console.error('>> Application is ready to use <<'); - }); -})); diff --git a/windows/app/install.js b/windows/app/install.js new file mode 120000 index 0000000..739468a --- /dev/null +++ b/windows/app/install.js @@ -0,0 +1 @@ +../../install-windows.js \ No newline at end of file diff --git a/windows/app/messaging.js b/windows/app/messaging.js deleted file mode 100644 index d62ec9c..0000000 --- a/windows/app/messaging.js +++ /dev/null @@ -1,128 +0,0 @@ -// chrome-native-messaging module -// -// Defines three Transform streams: -// -// - Input - transform native messages to JavaScript objects -// - Output - transform JavaScript objects to native messages -// - Transform - transform message objects to reply objects -// - Debug - transform JavaScript objects to lines of JSON (for debugging, obviously) - -var stream = require('stream'); -var util = require('util'); - -function Input() { - stream.Transform.call(this); - - // Transform bytes... - this._writableState.objectMode = false; - // ...into objects. - this._readableState.objectMode = true; - - // Unparsed data. - this.buf = new Buffer(0); - // Parsed length. - this.len = null; -} - -util.inherits(Input, stream.Transform); - -Input.prototype._transform = function(chunk, encoding, done) { - // Save this chunk. - this.buf = Buffer.concat([ this.buf, chunk ]); - - var self = this; - - function parseBuf() { - // Do we have a length yet? - if (typeof self.len !== 'number') { - // Nope. Do we have enough bytes for the length? - if (self.buf.length >= 4) { - // Yep. Parse the bytes. - self.len = self.buf.readUInt32LE(0); - // Remove the length bytes from the buffer. - self.buf = self.buf.slice(4); - } - } - - // Do we have a length yet? (We may have just parsed it.) - if (typeof self.len === 'number') { - // Yep. Do we have enough bytes for the message? - if (self.buf.length >= self.len) { - // Yep. Slice off the bytes we need. - var message = self.buf.slice(0, self.len); - // Remove the bytes for the message from the buffer. - self.buf = self.buf.slice(self.len); - // Clear the length so we know we need to parse it again. - self.len = null; - // Parse the message bytes. - var obj = JSON.parse(message.toString()); - // Enqueue it for reading. - self.push(obj); - // We could have more messages in the buffer so check again. - parseBuf(); - } - } - } - - // Check for a parsable buffer (both length and message). - parseBuf(); - - // We're done. - done(); -}; - -function Output() { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = false; -} - -util.inherits(Output, stream.Transform); - -Output.prototype._transform = function(chunk, encoding, done) { - var len = new Buffer(4); - var buf = new Buffer(JSON.stringify(chunk)); - - len.writeUInt32LE(buf.length, 0); - - this.push(len); - this.push(buf); - - done(); -}; - -function Transform(handler) { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = true; - - this.handler = handler; -} - -util.inherits(Transform, stream.Transform); - -Transform.prototype._transform = function(msg, encoding, done) { - this.handler(msg, this.push.bind(this), done); -}; - -function Debug() { - stream.Transform.call(this); - - this._writableState.objectMode = true; - this._readableState.objectMode = false; -} - -util.inherits(Debug, stream.Transform); - -Debug.prototype._transform = function(chunk, encoding, done) { - this.push(JSON.stringify(chunk) + '\n'); - - done(); -}; - -exports.Input = Input; -exports.Output = Output; -exports.Transform = Transform; -exports.Debug = Debug; diff --git a/windows/app/messaging.js b/windows/app/messaging.js new file mode 120000 index 0000000..ee7b302 --- /dev/null +++ b/windows/app/messaging.js @@ -0,0 +1 @@ +../../messaging.js \ No newline at end of file