Skip to content

Commit

Permalink
v0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-portmen committed Dec 5, 2016
0 parents commit 1a77068
Show file tree
Hide file tree
Showing 18 changed files with 985 additions and 0 deletions.
5 changes: 5 additions & 0 deletions linux/ReadMe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
To install the native application
1. Open a terminal window and point it into this directory
2. run ./install.sh

Note: The script needs administrator permission (sudo) to copy files successfully.
69 changes: 69 additions & 0 deletions linux/app/host.js
Original file line number Diff line number Diff line change
@@ -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);
115 changes: 115 additions & 0 deletions linux/app/install.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
'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: ['mbpegmnngblolkfjoegdinohffomfljn'],
firefox: ['[email protected]']
};

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\nnode 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 <<');
});
}));
128 changes: 128 additions & 0 deletions linux/app/messaging.js
Original file line number Diff line number Diff line change
@@ -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;
12 changes: 12 additions & 0 deletions linux/install.sh
Original file line number Diff line number Diff line change
@@ -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
else
echo Installer is using the attached node.js
sudo ../node install.js --add_node
fi

Binary file added linux/node
Binary file not shown.
5 changes: 5 additions & 0 deletions mac/ReadMe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
To install the native application
1. Open a terminal window and point it into this directory
2. run ./install.sh

Note: The script needs administrator permission (sudo) to copy files successfully.
Loading

0 comments on commit 1a77068

Please sign in to comment.