Skip to content

Commit

Permalink
Added initial support for Hydna Push.
Browse files Browse the repository at this point in the history
  • Loading branch information
jfd committed Sep 16, 2013
1 parent f8fae08 commit ccd4457
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 1 deletion.
14 changes: 14 additions & 0 deletions README.md
Expand Up @@ -86,6 +86,20 @@ Sets the origin identity that should be sent to the server on handshake.
Sets the agent identity that should be sent to the server on handshake.


### hydna.send(url, data, [prio=0], [callback])

Send's a message to specified `'url'` whithout creating a new `hydna.Channel` instance.

Note: This function is a complement to the ordinary Hydna Channel and should be used when a persistent connection is redundant.


### hydna.dispatch(url, data, [prio=0], [callback])

Dispatch a signal on the specified `'url'` whithout creating a new `hydna.Channel` instance.

Note: This function is a complement to the ordinary Hydna Channel and should be used when a persistent connection is redundant.


### hydna.createChannel(url, mode, [callback])

Opens a Channel to the specified ´'url'´.
Expand Down
156 changes: 155 additions & 1 deletion index.js
Expand Up @@ -40,7 +40,6 @@ var VERSION = require('./package.json').version;

var STATUS_CODES = require('http').STATUS_CODES;


var READ = 0x01;
var WRITE = 0x02;
var READWRITE = 0x03;
Expand All @@ -57,6 +56,8 @@ var MODE_RE = /^(r|read){0,1}(w|write){0,1}(?:\+){0,1}(e|emit){0,1}$/i;
exports.PAYLOAD_MAX_SIZE = PAYLOAD_MAX_SIZE;

exports.createChannel = createChannel;
exports.send = send;
exports.dispatch = dispatch;

exports.Channel = Channel;
exports.Connection = Connection;
Expand All @@ -76,6 +77,115 @@ function createChannel (url, mode, C) {
};


function send (url, data, prio, C) {
var headers;
var payload;
var url;

if (typeof prio == 'function') {
C = prio;
prio = 0;
}

url = parseHydnaUrl(url);

payload = typeof data == 'string' ? new Buffer(data, 'utf8') : data;

if (Buffer.isBuffer(payload) == false) {
throw new Error('Expected "data" as String or Buffer');
}

if (payload.length > PAYLOAD_MAX_SIZE) {
throw new Error('Payload overflow');
}

headers = {
'agent': exports.agent,
'X-Priority': String(prio),
'Content-Type': 'text/plain',
'Content-Length': payload.length
};

writeHttpRequest(url, payload, headers, C);
}


function dispatch (url, data, C) {
var headers;
var payload;
var url;

url = parseHydnaUrl(url);

payload = typeof data == 'string' ? new Buffer(data, 'utf8') : data;

if (Buffer.isBuffer(payload) == false) {
throw new Error('Expected "data" as String or Buffer');
}

if (payload.length > PAYLOAD_MAX_SIZE) {
throw new Error('Payload overflow');
}

headers = {
'agent': exports.agent,
'X-Emit': 'yes',
'Content-Type': 'text/plain',
'Content-Length': payload.length
};

writeHttpRequest(url, payload, headers, C);
}


function writeHttpRequest (url, payload, headers, C) {
var options;
var request;
var req;

request = url.protocol == 'http:' ? requestHttp : requestHttps;

options = {
hostname: url.hostname,
port: url.port || 80,
path: url.path,
method: 'POST',
headers: headers
};

req = request(options, function (res) {
var data;

if (typeof C !== 'function') {
return;
}

if (res.statusCode == 200) {
return C();
}

res.setEncoding('utf8');

res.on('data', function (chunk) {
data += chunk;
});

res.on('close', function () {
var err;
err = new Error(data || 'HTTP_' + res.statusCode);
return C(err);
});
});

req.on('error', function (err) {
return C && C(err);
});

req.write(payload);
req.end();
}


function Channel() {
this.id = null;

Expand Down Expand Up @@ -1448,3 +1558,47 @@ function getBinMode(modeExpr) {

return result;
}


function parseHydnaUrl(url) {
var channel;

if (typeof url !== 'string') {
throw new Error('bad argument, `url`, expected String');
}

if (/^http:\/\/|^https:\/\//.test(url) == false) {
url = 'http://' + url;
}

url = parseUrl(url);

if (url.protocol !== 'https:' && url.protocol !== 'http:') {
throw new Error('bad protocol, expected `http` or `https`');
}

if (url.pathname && url.pathname.length != 1) {
if (url.pathname.substr(0, 2) == '/x') {
channel = parseInt('0' + url.pathname.substr(1));
} else {
channel = parseInt(url.pathname.substr(1));
}
if (isNaN(channel)) {
throw new Error('Invalid channel');
}
} else {
channel = 1;
}

if (channel > 0xFFFFFFFF) {
throw new Error('Invalid channel expected no between x0 and xFFFFFFFF');
}

url.channel = channel;

if (url.query) {
url.token = new Buffer(decodeURIComponent(url.query), 'utf8');
}

return url;
}

0 comments on commit ccd4457

Please sign in to comment.