Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
123 lines
3.5 KiB
JavaScript
Executable file
123 lines
3.5 KiB
JavaScript
Executable file
/* global bridge,
|
|
BroadcastChannel,
|
|
EventDispatcher
|
|
*/
|
|
|
|
(function(exports) {
|
|
'use strict';
|
|
|
|
/**
|
|
* Name of the service that is responsible for managing activities.
|
|
* @type {string}
|
|
*/
|
|
const SERVICE_NAME = 'activity-service';
|
|
|
|
/**
|
|
* Reference to active bridge client instance. For every app instance that is
|
|
* run as inline activity we have only one bridge service (hosted in the main
|
|
* window context) and only one bridge client (hosted in the same context).
|
|
* Client should only communicate with the service that holds reference to
|
|
* the corresponding activity request. Since we can potentially have more than
|
|
* one inline activity instance we should use unique bridge service name for
|
|
* every app instance to avoid message collision.
|
|
*
|
|
* @type {Client}
|
|
*/
|
|
var client;
|
|
|
|
/**
|
|
* Indicates if there is pending activity request.
|
|
* @type {boolean}
|
|
*/
|
|
var hasPendingRequest;
|
|
|
|
/**
|
|
* ActivityClient is a wrapper around bridge client connected to the bridge
|
|
* service hosted in the context that can handle system messages. It allows
|
|
* to access "activity" request coming from system message when consumer can't
|
|
* receive it directly (document in a different URL or even worker).
|
|
* @type {Object}
|
|
*/
|
|
var ActivityClient = {
|
|
/**
|
|
* Initialized activity bridge client.
|
|
* @param {string} appInstanceId Unique identifier of app instance where
|
|
* client resides in.
|
|
*/
|
|
init(appInstanceId) {
|
|
if (!appInstanceId) {
|
|
throw new Error('AppInstanceId is required!');
|
|
}
|
|
|
|
client = bridge.client({
|
|
service: SERVICE_NAME,
|
|
endpoint: new BroadcastChannel(
|
|
`${SERVICE_NAME}-channel-${appInstanceId}`
|
|
),
|
|
// Disable service response timeouts.
|
|
timeout: false
|
|
});
|
|
hasPendingRequest = false;
|
|
|
|
client.on('activity-request', (request) => {
|
|
// This case should never happen since we use "inline" activities only.
|
|
if (hasPendingRequest) {
|
|
this.postError('Concurrent activity requests are not allowed');
|
|
return;
|
|
}
|
|
|
|
hasPendingRequest = true;
|
|
this.emit(request.name + '-activity-request', request.data);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Posts results to the activity caller.
|
|
* @param {*?} result
|
|
* @returns {Promise} Promise that resolves once operation is completed.
|
|
*/
|
|
postResult(result) {
|
|
if (!hasPendingRequest) {
|
|
return Promise.reject(
|
|
new Error('There is no any activity request to post result to!')
|
|
);
|
|
}
|
|
|
|
hasPendingRequest = false;
|
|
return client.method('postResult', result);
|
|
},
|
|
|
|
/**
|
|
* Notifies activity caller that exception occurred.
|
|
* @param {*?} error
|
|
* @returns {Promise} Promise that resolves once operation is completed.
|
|
*/
|
|
postError(error) {
|
|
if (!hasPendingRequest) {
|
|
return Promise.reject(
|
|
new Error('There is no any activity request to post error to!')
|
|
);
|
|
}
|
|
|
|
hasPendingRequest = false;
|
|
|
|
console.error('Activity request was rejected with "%s" reason', error);
|
|
|
|
return client.method('postError', error);
|
|
},
|
|
|
|
/**
|
|
* Checks if client has pending activity request.
|
|
* @returns {boolean}
|
|
*/
|
|
hasPendingRequest() {
|
|
return hasPendingRequest;
|
|
}
|
|
};
|
|
|
|
exports.ActivityClient = Object.freeze(
|
|
EventDispatcher.mixin(
|
|
ActivityClient, ['new-activity-request', 'share-activity-request']
|
|
)
|
|
);
|
|
})(window);
|