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.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
197
gaia/apps/sms/lib/bridge/plugins/stream/client.js
Executable file
197
gaia/apps/sms/lib/bridge/plugins/stream/client.js
Executable file
|
|
@ -0,0 +1,197 @@
|
|||
!((define)=>{define((require,exports,module)=>{
|
||||
|
||||
/**
|
||||
* Mini Logger
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
var debug = 0 ? function(arg1, ...args) {
|
||||
var type = `[${self.constructor.name}][${location.pathname}]`;
|
||||
console.log(`[ClientStream]${type} - "${arg1}"`, ...args);
|
||||
} : () => {};
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = (client, utils) => {
|
||||
client._activeStreams = [];
|
||||
client.on('streamevent', onStreamEvent);
|
||||
|
||||
client.stream = function(name) {
|
||||
debug('stream open', name);
|
||||
var args = [].slice.call(arguments, 1);
|
||||
var stream = new ClientStream(client, utils);
|
||||
var self = this;
|
||||
|
||||
this.method('_stream', name, stream.id, this.id, args)
|
||||
.then(() => {
|
||||
debug('stream connected', name);
|
||||
stream._connected.resolve();
|
||||
})
|
||||
|
||||
.catch(err => {
|
||||
debug('error', err);
|
||||
onStreamEvent({
|
||||
type: 'abort',
|
||||
id: stream.id,
|
||||
data: err
|
||||
});
|
||||
});
|
||||
|
||||
this._activeStreams[stream.id] = stream;
|
||||
stream.emitter.on('cancel', onEnd);
|
||||
stream.emitter.on('abort', onEnd);
|
||||
stream.emitter.on('close', onEnd);
|
||||
|
||||
function onEnd() {
|
||||
debug('end');
|
||||
delete self._activeStreams[stream.id];
|
||||
stream.destroy();
|
||||
}
|
||||
|
||||
return stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called every time the service calls
|
||||
* write/abort/close on the ServiceStream
|
||||
*
|
||||
* @param {Object} broadcast
|
||||
* @param {String} broadcast.id Stream ID
|
||||
* @param {String} broadcast.type Event type ('write', 'abort' or 'close')
|
||||
* @private
|
||||
*/
|
||||
|
||||
function onStreamEvent(data) {
|
||||
debug('stream event', data.type);
|
||||
var stream = client._activeStreams[data.streamId];
|
||||
stream.emitter.emit(data.type, data.data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Readable stream instance returned by
|
||||
* a `client.stream('methodName')` call.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {String} options.id Stream Id, used to match client/service streams
|
||||
* @param {Client} options.client Client instance
|
||||
*/
|
||||
|
||||
function ClientStream(client, utils) {
|
||||
this.id = utils.uuid();
|
||||
this.client = client;
|
||||
this.emitter = new utils.Emitter();
|
||||
this.emitter.on('close', this.onClose.bind(this));
|
||||
this.emitter.on('abort', this.onAbort.bind(this));
|
||||
this._connected = defer();
|
||||
this.connected = this._connected.promise;
|
||||
this._closed = defer();
|
||||
this.closed = this._closed.promise;
|
||||
debug('initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prototype assigned to variable
|
||||
* to improve compression.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
ClientStream.prototype = {
|
||||
|
||||
/**
|
||||
* Add a listener that will be called
|
||||
* every time the service broadcasts
|
||||
* a new chunk of data.
|
||||
*
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
listen(callback) {
|
||||
debug('listen', callback);
|
||||
this.emitter.on('write', callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes 'data' listener
|
||||
*
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
unlisten(callback) {
|
||||
debug('unlisten', callback);
|
||||
this.emitter.off('write', callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify the service that
|
||||
* action should be canceled
|
||||
*
|
||||
* @param {*} [reason] Optional data to be sent to service.
|
||||
*/
|
||||
|
||||
cancel(reason) {
|
||||
debug('cancel', reason);
|
||||
return this.client.method('_streamcancel', this.id, reason)
|
||||
.then(result => {
|
||||
debug('cancelled', result);
|
||||
this.emitter.emit('cancel');
|
||||
return result;
|
||||
})
|
||||
|
||||
.catch(e => {
|
||||
this.emitter.emit('cancel');
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Used internally by Client when
|
||||
* it receives an 'abort' event
|
||||
* from the service.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
onAbort(reason) {
|
||||
debug('abort', reason);
|
||||
this._closed.reject(reason);
|
||||
},
|
||||
|
||||
/**
|
||||
* Used internally by Client when
|
||||
* it receives a 'close' event
|
||||
* from the service.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
onClose() {
|
||||
debug('close');
|
||||
this._closed.resolve();
|
||||
},
|
||||
|
||||
destroy() {
|
||||
debug('destroy');
|
||||
this.emitter.off();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
function defer() {
|
||||
var result = {};
|
||||
result.promise = new Promise((resolve, reject) => {
|
||||
result.resolve = resolve;
|
||||
result.reject = reject;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
});})((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;};})('streamClient',this));
|
||||
206
gaia/apps/sms/lib/bridge/plugins/stream/service.js
Executable file
206
gaia/apps/sms/lib/bridge/plugins/stream/service.js
Executable file
|
|
@ -0,0 +1,206 @@
|
|||
!((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));
|
||||
Loading…
Reference in a new issue