joynr.messaging.channel.ChannelMessagingSender.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of libjoynr-js Show documentation
Show all versions of libjoynr-js Show documentation
JOYnr JavaScript libjoynr-js
/*jslint es5: true, undef: true */// problem with functions postMessage and resend calling each other => it is not possible to bring them in an order without having the jslint "was not defined" error
/*
* #%L
* %%
* Copyright (C) 2011 - 2015 BMW Car IT GmbH
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
define("joynr/messaging/channel/ChannelMessagingSender", [
"global/Promise",
"joynr/util/UtilInternal",
"joynr/util/Typing",
"joynr/util/JSONSerializer",
"joynr/messaging/JoynrMessage",
"joynr/util/LongTimer",
"joynr/system/DiagnosticTags",
"joynr/system/LoggerFactory"
], function(Promise, Util, Typing, JSONSerializer, JoynrMessage, LongTimer, DiagnosticTags, LoggerFactory) {
/**
* ChannelMessagingSender sends JoynrMessages to their destinations via Http
*
* @constructor
* @name ChannelMessagingSender
* @param {Object}
* settings the settings object holding the dependencies
* @param {LocalChannelUrlDirectory}
* settings.channelUrlDirectory
*/
function ChannelMessagingSender(settings) {
var log = LoggerFactory.getLogger("joynr.messaging.ChannelMessagingSender");
var messageQueue = []; // use push to add at the back, and shift to take from the front
var messageProcessors = settings.channelQos && settings.channelQos.messageProcessors ? settings.channelQos.messageProcessors : 4;
var resendDelay_ms = settings.channelQos && settings.channelQos.resendDelay_ms ? settings.channelQos.resendDelay_ms : 1000;
var channelUrlDirectory = settings.channelUrlDirectory;
var communicationModule = settings.communicationModule;
var started = false;
var getRelativeExpiryDate = function getRelativeExpiryDate(joynrMessage) {
return parseInt(joynrMessage.header[JoynrMessage.JOYNRMESSAGE_HEADER_EXPIRYDATE], 10) - Date.now();
};
var checkIfExpired = function(queuedMessage){
if (queuedMessage.pending === false || queuedMessage.expiryTimer === undefined) {
return true;
}
var isExpired = getRelativeExpiryDate(queuedMessage.message) <= 0;
if (isExpired) {
queuedMessage.pending = false;
LongTimer.clearTimeout(queuedMessage.expiryTimer);
delete queuedMessage.expiryTimer;
var errMsg = "DISCARDED " + JSONSerializer.stringify(queuedMessage) + ": ttl expired";
log.warn(errMsg);
queuedMessage.reject(new Error(errMsg));
}
return isExpired;
};
this.start = function(){
started = true;
notify();
};
/**
* Sends the message to the given url
*
* @name ChannelMessagingSender#postMessage
* @function
* @private
* @param {JoynrMessage}
* queuedMessage to be sent
*/
function postMessage(queuedMessage) {
var timeout = queuedMessage.expiryDate - Date.now();
// XMLHttpRequest uses a timeout of 0 to mean that there is no timeout.
// ttl = 0 means the opposite (is already expired)
if (timeout <= 0) {
timeout = -1;
}
messageProcessors--;
log.info("sending message. timeout in (ms): " + timeout, JSONSerializer.stringify(DiagnosticTags
.forJoynrMessage(queuedMessage.message)));
log.trace("sending message. timeout in (ms): "
+ timeout
+ JSONSerializer.stringify(queuedMessage.message, undefined, 4));
communicationModule.createXMLHTTPRequest({
type : "POST",
url : queuedMessage.to,
data : JSONSerializer.stringify(queuedMessage.message),
timeout : timeout
}).then(
function(xhr) {
try {
log.debug("sending msgId: "
+ queuedMessage.message.msgId
+ " completed successfully");
queuedMessage.pending = false;
LongTimer.clearTimeout(queuedMessage.expiryTimer);
delete queuedMessage.expiryTimer;
queuedMessage.resolve();
} catch (error) {
log.error("sending msgId: "
+ queuedMessage.message.msgId
+ " deferred caused an exception");
}
messageProcessors++;
notify();
}).catch(function(xhr, errorType) {
try {
log.debug("sending msgId: " + queuedMessage.message.msgId + " failed");
resend(queuedMessage);
} catch (error) {
log.error("sending msgId: "
+ queuedMessage.message.msgId
+ " deferred.reject caused an exception");
}
messageProcessors++;
notify();
});
}
/**
* If a processor is available to send the message, use it, otherwise will wait until one is
* ready
*
* @name ChannelMessagingSender#notify
* @function
* @private
*/
function notify() {
if (messageProcessors > 0 && started) {
var nextMessage = messageQueue.shift();
if (nextMessage === undefined) {
return;
}
postMessage(nextMessage);
}
}
/**
* Sends a JoynrMessage to the given channel Id.
*
* @name ChannelMessagingSender#send
* @function
* @param {JoynrMessage}
* joynrMessage - message to be sent. Must be an instanceof JoynrMessage.
* @param {String}
* toChannel - channel Id of recipient.
* @returns {Object} a promise object for async event handling
*/
this.send =
function send(joynrMessage, toChannel) {
if (!joynrMessage instanceof JoynrMessage) {
return Promise.reject(new Error(
"CANNOT SEND: invalid joynrMessage which is of type "
+ Typing.getObjectType(joynrMessage)));
}
return channelUrlDirectory.getUrlsForChannel({
channelId : toChannel
}).then(function(channelUrlInformation) {
return new Promise(function(resolve, reject) {
var queuedMessage = {
message : joynrMessage,
to : channelUrlInformation.urls[0]
+ "messageWithoutContentType/",
resolve : resolve,
reject : reject,
pending : true,
expiryTimer : LongTimer.setTimeout(function(){
checkIfExpired(queuedMessage);
}, getRelativeExpiryDate(joynrMessage))
};
messageQueue.push(queuedMessage);
LongTimer.setTimeout(notify, 0);
});
}).catch(function(error) {
throw new Error("Could not get URL for channel '"
+ toChannel + "': " + error);
});
};
/**
* Resend in the event of an error, and call the error callback if the ttl is
expired.
*
* @name ChannelMessagingSender#resend
* @function
* @private
*
* @param {JoynrMessage}
* queuedMessage
*/
function resend(queuedMessage) {
if (checkIfExpired(queuedMessage)) {
return;
}
// resend the message
LongTimer.setTimeout(function() {
postMessage(queuedMessage);
}, resendDelay_ms);
}
}
return ChannelMessagingSender;
});
© 2015 - 2025 Weber Informatics LLC | Privacy Policy