// (c) 2010 Jeff Mesnil -- http://jmesnil.net/
|
// Copyright (C) FuseSource, Inc. -- http://fusesource.com
|
|
(function(window) {
|
|
var Stomp = {};
|
|
Stomp.frame = function(command, headers, body) {
|
return {
|
command: command,
|
headers: headers,
|
body: body,
|
toString: function() {
|
var out = command + '\n';
|
if (headers) {
|
for (header in headers) {
|
if(headers.hasOwnProperty(header)) {
|
out = out + header + ': ' + headers[header] + '\n';
|
}
|
}
|
}
|
out = out + '\n';
|
if (body) {
|
out = out + body;
|
}
|
return out;
|
}
|
}
|
};
|
|
trim = function(str) {
|
return str.replace(/^\s+/g,'').replace(/\s+$/g,'');
|
};
|
|
Stomp.unmarshal = function(data) {
|
var divider = data.search(/\n\n/),
|
headerLines = data.substring(0, divider).split('\n'),
|
command = headerLines.shift(),
|
headers = {},
|
body = '';
|
|
// Parse headers
|
var line = idx = null;
|
for (var i = 0; i < headerLines.length; i++) {
|
line = headerLines[i];
|
idx = line.indexOf(':');
|
headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));
|
}
|
|
// Parse body, stopping at the first \0 found.
|
// TODO: Add support for content-length header.
|
var chr = null;
|
for (var i = divider + 2; i < data.length; i++) {
|
chr = data.charAt(i);
|
if (chr === '\0') {
|
break;
|
}
|
body += chr;
|
}
|
|
return Stomp.frame(command, headers, body);
|
};
|
|
Stomp.marshal = function(command, headers, body) {
|
return Stomp.frame(command, headers, body).toString() + '\0';
|
};
|
|
Stomp.client = function (url){
|
|
var that, ws, login, passcode;
|
var counter = 0; // used to index subscribers
|
// subscription callbacks indexed by subscriber's ID
|
var subscriptions = {};
|
|
debug = function(str) {
|
if (that.debug) {
|
that.debug(str);
|
}
|
};
|
|
onmessage = function(evt) {
|
var data = evt.data
|
if (data instanceof ArrayBuffer) {
|
view = new Uint8Array(data);
|
data = "";
|
var i, len;
|
for (i = 0, len = view.length; i < len; i++) {
|
data += String.fromCharCode(view[i]);
|
}
|
}
|
debug('<<< ' + data);
|
var frame = Stomp.unmarshal(data);
|
if (frame.command === "CONNECTED" && that.connectCallback) {
|
that.connectCallback(frame);
|
} else if (frame.command === "MESSAGE") {
|
var onreceive = subscriptions[frame.headers.subscription];
|
if (onreceive) {
|
onreceive(frame);
|
}
|
} else if (frame.command === "RECEIPT" && that.onreceipt) {
|
that.onreceipt(frame);
|
} else if (frame.command === "ERROR" && that.onerror) {
|
that.onerror(frame);
|
}
|
};
|
|
transmit = function(command, headers, body) {
|
var out = Stomp.marshal(command, headers, body);
|
debug(">>> " + out);
|
ws.send(out);
|
};
|
|
that = {};
|
|
that.connect = function(login_, passcode_, connectCallback, errorCallback) {
|
debug("Opening Web Socket...");
|
var Socket = "MozWebSocket" in window ? MozWebSocket : WebSocket;
|
ws = new Socket(url);
|
ws.binaryType = "arraybuffer";
|
ws.onmessage = onmessage;
|
ws.onclose = function() {
|
var msg = "Whoops! Lost connection to " + url;
|
debug(msg);
|
if (errorCallback) {
|
errorCallback(msg);
|
}
|
};
|
ws.onopen = function() {
|
debug('Web Socket Opened...');
|
transmit("CONNECT", {login: login, passcode: passcode});
|
// connectCallback handler will be called from onmessage when a CONNECTED frame is received
|
};
|
login = login_;
|
passcode = passcode_;
|
that.connectCallback = connectCallback;
|
};
|
|
that.disconnect = function(disconnectCallback) {
|
transmit("DISCONNECT");
|
ws.close();
|
if (disconnectCallback) {
|
disconnectCallback();
|
}
|
};
|
|
that.send = function(destination, headers, body) {
|
var headers = headers || {};
|
headers.destination = destination;
|
transmit("SEND", headers, body);
|
};
|
|
that.subscribe = function(destination, callback, headers) {
|
var headers = headers || {};
|
var id = "sub-" + counter++;
|
headers.destination = destination;
|
headers.id = id;
|
subscriptions[id] = callback;
|
transmit("SUBSCRIBE", headers);
|
return id;
|
};
|
|
that.unsubscribe = function(id, headers) {
|
var headers = headers || {};
|
headers.id = id;
|
delete subscriptions[id];
|
transmit("UNSUBSCRIBE", headers);
|
};
|
|
that.begin = function(transaction, headers) {
|
var headers = headers || {};
|
headers.transaction = transaction;
|
transmit("BEGIN", headers);
|
};
|
|
that.commit = function(transaction, headers) {
|
var headers = headers || {};
|
headers.transaction = transaction;
|
transmit("COMMIT", headers);
|
};
|
|
that.abort = function(transaction, headers) {
|
var headers = headers || {};
|
headers.transaction = transaction;
|
transmit("ABORT", headers);
|
};
|
|
that.ack = function(message_id, headers) {
|
var headers = headers || {};
|
headers["message-id"] = message_id;
|
transmit("ACK", headers);
|
};
|
return that;
|
};
|
|
window.Stomp = Stomp;
|
|
})(window);
|