VulpesOS/gaia/apps/sms/lib/bridge/plugins/stream/service.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

206 lines
4.8 KiB
JavaScript
Executable file

!((define)=>{define((require,exports,module)=>{
/**
* Mini Logger
*
* @type {Function}
*/
var debug = 0 ? function(arg1, ...args) {
var type = `[${self.constructor.name}][${location.pathname}]`;
console.log(`[ServiceStream]${type} - "${arg1}"`, ...args);
} : () => {};
module.exports = function(service) {
debug('attaching plugin');
service
.method('_stream', onStream)
.method('_streamcancel', onStreamCancel);
service._streamHandlers = {};
service._activeStreams = [];
service.stream = function(name, fn) {
debug('register stream', name);
this._streamHandlers[name] = fn;
return this;
};
function onStream(name, id, clientId, args) {
debug('on stream open', name);
var e = {
preventDefault: () => e.defaultPrevented = true,
arguments: arguments
};
// Allow other plugins to override default behaviour
service.emit('before-stream', e);
if (e.defaultPrevented) return;
var fn = service._streamHandlers[name];
if (!fn) throw error(1, name);
var stream = new ServiceStream(id, service, clientId);
service._activeStreams[id] = stream;
// Always pass stream object as first
// argument to simplify the process
fn.apply(service, [stream].concat(args));
}
function onStreamCancel(id, reason) {
debug('stream cancel');
var stream = service._activeStreams[id];
delete service._activeStreams[id];
return stream.cancel(reason);
}
};
/**
* Writable Stream instance passed to the
* `service.stream` implementation
*
* @param {Object} options
* @param {String} options.id Stream ID used to sync client and service streams
* @param {BroadcastChannel} options.channel Channel used to postMessage
* @param {String} options.serviceId ID of the service
* @param {String} options.clientId ID of client that should receive message
*/
function ServiceStream(streamId, service, clientId) {
this.id = streamId;
this.service = service;
this.clientId = clientId;
this.writable = true;
debug('initialized');
}
/**
* Prototype assigned to variable
* to improve compression.
*
* @type {Object}
*/
var ServiceStreamPrototype = ServiceStream.prototype;
/**
* Services that allows clients to
* cancel the operation before it's
* complete should override the
* `stream.cancel` method.
*
* @param {*} [reason] Data sent from client about the cancellation
* @returns {(Promise|*)}
*/
ServiceStreamPrototype.cancel = function(reason) {
var err = new TypeError('service should implement stream.cancel()');
return Promise.reject(err);
};
/**
* Signal to client that action was
* aborted during the process, this
* should be used as a way to
* communicate errors.
*
* @param {*} [data] Reason of failure
* @returns {Promise}
* @public
*/
ServiceStreamPrototype.abort = function(data) {
debug('abort', data);
this._post('abort', data);
this.writable = false;
};
/**
* Sends a chunk of data to the client.
*
* @param {*} data Chunk of data to be sent to client.
* @returns {Promise}
* @public
*/
ServiceStreamPrototype.write = function(data) {
debug('write', data);
this._post('write', data);
};
/**
* Closes the stream, signals that
* action was completed with success.
*
* According to whatwg streams spec,
* WritableStream#close() doesn't send data.
*
* @returns {Promise}
*/
ServiceStreamPrototype.close = function() {
debug('close');
this._post('close');
this.writable = false;
};
/**
* Validate the current state and
* call cancel on the target stream.
*
* Called by the Service when client
* sends a 'streamcancel' message.
*
* @param {*} [reason] Reason for cancelation sent by the client
* @returns {Promise}
* @private
*/
ServiceStreamPrototype._cancel = function(reason) {
debug('cancel', reason);
return this.cancel(reason)
.then(result => {
this.writable = false;
return result;
});
};
/**
* Validate the current state and post message to client.
*
* @param {String} type 'write', 'abort' or 'close'
* @param {String} state 'writable', 'aborted' or 'closed'
* @param {*} [data] Data to be sent to the client
* @returns {Promise}
* @private
*/
ServiceStreamPrototype._post = function(type, data) {
debug('post', type, data, this.writable);
if (!this.writable) return Promise.reject();
this.service.broadcast('streamevent', {
streamId: this.id,
type: type,
data: data
}, [this.clientId]);
};
/**
* Create new `Error` from registery.
*
* @param {Number} id Error Id
* @return {Error}
* @private
*/
function error(id) {
var args = [].slice.call(arguments, 1);
return new Error({
1: 'stream "' + args[0] + '" doesn\'t exist'
}[id]);
}
});})((typeof define)[0]=='f'&&define.amd?define:((n,w)=>{return(typeof
module)[0]=='o'?c=>{c(require,exports,module);}:(c)=>{var m={exports:{}};
c(n=>w[n],m.exports,m);w[n]=m.exports;};})('streamService',this));