jsforce2
Version:
Salesforce API Library for JavaScript
137 lines (125 loc) • 3.88 kB
JavaScript
/**
* Faye Client extensions: https://faye.jcoglan.com/browser/extensions.html
*
* For use with Streaming.prototype.createClient()
**/
var StreamingExtension = {};
/**
* Constructor for an auth failure detector extension
*
* Based on new feature released with Salesforce Spring '18:
* https://releasenotes.docs.salesforce.com/en-us/spring18/release-notes/rn_messaging_cometd_auth_validation.htm?edition=&impact=
*
* Example triggering error message:
*
* ```
* {
* "ext":{
* "sfdc":{"failureReason":"401::Authentication invalid"},
* "replay":true},
* "advice":{"reconnect":"none"},
* "channel":"/meta/handshake",
* "error":"403::Handshake denied",
* "successful":false
* }
* ```
*
* Example usage:
*
* ```javascript
* const conn = new jsforce.Connection({ … });
*
* const channel = "/event/My_Event__e";
*
* // Exit the Node process when auth fails
* const exitCallback = () => process.exit(1);
* const authFailureExt = new jsforce.StreamingExtension.AuthFailure(exitCallback);
*
* const fayeClient = conn.streaming.createClient([ authFailureExt ]);
*
* const subscription = fayeClient.subscribe(channel, data => {
* console.log('topic received data', data);
* });
*
* subscription.cancel();
* ```
*
* @param {Function} failureCallback - Invoked when authentication becomes invalid
*/
StreamingExtension.AuthFailure = function(failureCallback) {
this.incoming = function(message, callback) {
if (
(message.channel === '/meta/connect' ||
message.channel === '/meta/handshake')
&& message.advice
&& message.advice.reconnect == 'none'
) {
failureCallback(message);
} else {
callback(message);
}
}
};
/**
* Constructor for a durable streaming replay extension
*
* Modified from original Salesforce demo source code:
* https://github.com/developerforce/SalesforceDurableStreamingDemo/blob/3d4a56eac956f744ad6c22e6a8141b6feb57abb9/staticresources/cometdReplayExtension.resource
*
* Example usage:
*
* ```javascript
* const conn = new jsforce.Connection({ … });
*
* const channel = "/event/My_Event__e";
* const replayId = -2; // -2 is all retained events
*
* const replayExt = new jsforce.StreamingExtension.Replay(channel, replayId);
*
* const fayeClient = conn.streaming.createClient([ replayExt ]);
*
* const subscription = fayeClient.subscribe(channel, data => {
* console.log('topic received data', data);
* });
*
* subscription.cancel();
* ```
*/
StreamingExtension.Replay = function(channel, replayId) {
var REPLAY_FROM_KEY = "replay";
var _extensionEnabled = replayId != null ? true : false;
var _replay = replayId;
var _channel = channel;
this.setExtensionEnabled = function(extensionEnabled) {
_extensionEnabled = extensionEnabled;
}
this.setReplay = function (replay) {
_replay = parseInt(replay, 10);
}
this.setChannel = function(channel) {
_channel = channel;
}
this.incoming = function(message, callback) {
if (message.channel === '/meta/handshake') {
if (message.ext && message.ext[REPLAY_FROM_KEY] == true) {
_extensionEnabled = true;
}
} else if (message.channel === _channel && message.data && message.data.event && message.data.event.replayId) {
_replay = message.data.event.replayId;
}
callback(message);
}
this.outgoing = function(message, callback) {
if (message.channel === '/meta/subscribe' && message.subscription === _channel) {
if (_extensionEnabled) {
if (!message.ext) { message.ext = {}; }
var replayFromMap = {};
replayFromMap[_channel] = _replay;
// add "ext : { "replay" : { CHANNEL : REPLAY_VALUE }}" to subscribe message
message.ext[REPLAY_FROM_KEY] = replayFromMap;
}
}
callback(message);
};
};
module.exports = StreamingExtension;