229 lines
6.8 KiB
JavaScript
Executable File
229 lines
6.8 KiB
JavaScript
Executable File
/*
|
|
* Copyright 2014 Red Hat, Inc.
|
|
*
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* and Apache License v2.0 which accompanies this distribution.
|
|
*
|
|
* The Eclipse Public License is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* The Apache License v2.0 is available at
|
|
* http://www.opensource.org/licenses/apache2.0.php
|
|
*
|
|
* You may elect to redistribute this code under either of these licenses.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2011-2013 The original author or authors
|
|
* ------------------------------------------------------
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* and Apache License v2.0 which accompanies this distribution.
|
|
*
|
|
* The Eclipse Public License is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* The Apache License v2.0 is available at
|
|
* http://www.opensource.org/licenses/apache2.0.php
|
|
*
|
|
* You may elect to redistribute this code under either of these licenses.
|
|
*/
|
|
|
|
var vertx = vertx || {};
|
|
|
|
!function(factory) {
|
|
if (typeof define === "function" && define.amd) {
|
|
// Expose as an AMD module with SockJS dependency.
|
|
// "vertxbus" and "sockjs" names are used because
|
|
// AMD module names are derived from file names.
|
|
define("vertxbus", ["sockjs"], factory);
|
|
} else {
|
|
// No AMD-compliant loader
|
|
factory(SockJS);
|
|
}
|
|
}(function(SockJS) {
|
|
|
|
vertx.EventBus = function(url, options) {
|
|
|
|
var that = this;
|
|
var sockJSConn = new SockJS(url, undefined, options);
|
|
var handlerMap = {};
|
|
var replyHandlers = {};
|
|
var state = vertx.EventBus.CONNECTING;
|
|
var pingTimerID = null;
|
|
var pingInterval = null;
|
|
if (options) {
|
|
pingInterval = options['vertxbus_ping_interval'];
|
|
}
|
|
if (!pingInterval) {
|
|
pingInterval = 5000;
|
|
}
|
|
|
|
that.onopen = null;
|
|
that.onclose = null;
|
|
|
|
that.send = function(address, message, replyHandler) {
|
|
sendOrPub("send", address, message, replyHandler)
|
|
}
|
|
|
|
that.publish = function(address, message) {
|
|
sendOrPub("publish", address, message, null)
|
|
}
|
|
|
|
that.registerHandler = function(address, handler) {
|
|
checkSpecified("address", 'string', address);
|
|
checkSpecified("handler", 'function', handler);
|
|
checkOpen();
|
|
var handlers = handlerMap[address];
|
|
if (!handlers) {
|
|
handlers = [handler];
|
|
handlerMap[address] = handlers;
|
|
// First handler for this address so we should register the connection
|
|
var msg = { type : "register",
|
|
address: address };
|
|
sockJSConn.send(JSON.stringify(msg));
|
|
} else {
|
|
handlers[handlers.length] = handler;
|
|
}
|
|
}
|
|
|
|
that.unregisterHandler = function(address, handler) {
|
|
checkSpecified("address", 'string', address);
|
|
checkSpecified("handler", 'function', handler);
|
|
checkOpen();
|
|
var handlers = handlerMap[address];
|
|
if (handlers) {
|
|
var idx = handlers.indexOf(handler);
|
|
if (idx != -1) handlers.splice(idx, 1);
|
|
if (handlers.length == 0) {
|
|
// No more local handlers so we should unregister the connection
|
|
|
|
var msg = { type : "unregister",
|
|
address: address};
|
|
sockJSConn.send(JSON.stringify(msg));
|
|
delete handlerMap[address];
|
|
}
|
|
}
|
|
}
|
|
|
|
that.close = function() {
|
|
checkOpen();
|
|
state = vertx.EventBus.CLOSING;
|
|
sockJSConn.close();
|
|
}
|
|
|
|
that.readyState = function() {
|
|
return state;
|
|
}
|
|
|
|
sockJSConn.onopen = function() {
|
|
// Send the first ping then send a ping every pingInterval milliseconds
|
|
sendPing();
|
|
pingTimerID = setInterval(sendPing, pingInterval);
|
|
state = vertx.EventBus.OPEN;
|
|
if (that.onopen) {
|
|
that.onopen();
|
|
}
|
|
};
|
|
|
|
sockJSConn.onclose = function() {
|
|
state = vertx.EventBus.CLOSED;
|
|
if (pingTimerID) clearInterval(pingTimerID);
|
|
if (that.onclose) {
|
|
that.onclose();
|
|
}
|
|
};
|
|
|
|
sockJSConn.onmessage = function(e) {
|
|
var msg = e.data;
|
|
var json = JSON.parse(msg);
|
|
var type = json.type;
|
|
if (type === 'err') {
|
|
console.error("Error received on connection: " + JSON.stringify(json));
|
|
return;
|
|
}
|
|
var body = json.body;
|
|
var replyAddress = json.replyAddress;
|
|
var address = json.address;
|
|
var replyHandler;
|
|
if (replyAddress) {
|
|
replyHandler = function(reply, replyHandler) {
|
|
// Send back reply
|
|
that.send(replyAddress, reply, replyHandler);
|
|
};
|
|
}
|
|
var handlers = handlerMap[address];
|
|
if (handlers) {
|
|
// We make a copy since the handler might get unregistered from within the
|
|
// handler itself, which would screw up our iteration
|
|
var copy = handlers.slice(0);
|
|
for (var i = 0; i < copy.length; i++) {
|
|
copy[i](body, replyHandler);
|
|
}
|
|
} else {
|
|
// Might be a reply message
|
|
var handler = replyHandlers[address];
|
|
if (handler) {
|
|
delete replyHandlers[address];
|
|
handler(body, replyHandler);
|
|
}
|
|
}
|
|
}
|
|
|
|
function sendPing() {
|
|
var msg = {
|
|
type: "ping"
|
|
}
|
|
sockJSConn.send(JSON.stringify(msg));
|
|
}
|
|
|
|
function sendOrPub(sendOrPub, address, message, replyHandler) {
|
|
checkSpecified("address", 'string', address);
|
|
checkSpecified("replyHandler", 'function', replyHandler, true);
|
|
checkOpen();
|
|
var envelope = { type : sendOrPub,
|
|
address: address,
|
|
body: message };
|
|
if (replyHandler) {
|
|
var replyAddress = makeUUID();
|
|
envelope.replyAddress = replyAddress;
|
|
replyHandlers[replyAddress] = replyHandler;
|
|
}
|
|
var str = JSON.stringify(envelope);
|
|
sockJSConn.send(str);
|
|
}
|
|
|
|
function checkOpen() {
|
|
if (state != vertx.EventBus.OPEN) {
|
|
throw new Error('INVALID_STATE_ERR');
|
|
}
|
|
}
|
|
|
|
function checkSpecified(paramName, paramType, param, optional) {
|
|
if (!optional && !param) {
|
|
throw new Error("Parameter " + paramName + " must be specified");
|
|
}
|
|
if (param && typeof param != paramType) {
|
|
throw new Error("Parameter " + paramName + " must be of type " + paramType);
|
|
}
|
|
}
|
|
|
|
function isFunction(obj) {
|
|
return !!(obj && obj.constructor && obj.call && obj.apply);
|
|
}
|
|
|
|
function makeUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
|
.replace(/[xy]/g,function(a,b){return b=Math.random()*16,(a=="y"?b&3|8:b|0).toString(16)})}
|
|
|
|
}
|
|
|
|
vertx.EventBus.CONNECTING = 0;
|
|
vertx.EventBus.OPEN = 1;
|
|
vertx.EventBus.CLOSING = 2;
|
|
vertx.EventBus.CLOSED = 3;
|
|
|
|
return vertx.EventBus;
|
|
|
|
});
|