VulpesOS/gaia/apps/sms/services/js/activity/activity_client.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

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);