Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUACAMOLE-1974: Allow deferring received pipe streams for later consumption by name-specific handlers. #1001

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 139 additions & 1 deletion guacamole/src/main/frontend/src/app/client/types/ManagedClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,49 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
*/
var THUMBNAIL_UPDATE_FREQUENCY = 5000;

/**
* A deferred pipe stream, that has yet to be consumed, as well as all
* axuilary information needed to pull data from the stream.
*
* @constructor
* @param {DeferredPipeStream|Object} [template={}]
* The object whose properties should be copied within the new
* DeferredPipeStream.
*/
var DeferredPipeStream = function DeferredPipeStream(template) {

// Use empty object by default
template = template || {};

/**
* The stream that will receive data from the server.
*
* @type Guacamole.InputStream
*/
this.stream = template.stream;

/**
* The mimetype of the data which will be received.
*
* @type String
*/
this.mimetype = template.mimetype;

/**
* The name of the pipe.
*
* @type String
*/
this.name = template.name;

};

/**
* Object which serves as a surrogate interface, encapsulating a Guacamole
* client while it is active, allowing it to be maintained in the
* background. One or more ManagedClients are grouped within
* ManagedClientGroups before being attached to the client view.
*
*
* @constructor
* @param {ManagedClient|Object} [template={}]
* The object whose properties should be copied within the new
Expand Down Expand Up @@ -240,6 +277,22 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
*/
this.arguments = template.arguments || {};

/**
* Any received pipe streams that have not been consumed by an onpipe
* handler or registered pipe handler, indexed by pipe stream name.
*
* @type {Object.<String, Object>}
*/
this.deferredPipeStreams = template.deferredPipeStreams || {};

/**
* Handlers for deferred pipe streams, indexed by the name of the pipe
* stream that the handler should handle.
*
* @type {Object.<String, Function>}
*/
this.deferredPipeStreamHandlers = template.deferredPipeStreamHandlers || {};

};

/**
Expand Down Expand Up @@ -553,6 +606,25 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',

};

// A default onpipe implementation that will automatically defer any
// received pipe streams, automatically invoking any registered handlers
// that may already be set for the received name
client.onpipe = (stream, mimetype, name) => {

// Defer the pipe stream
managedClient.deferredPipeStreams[name] = new DeferredPipeStream(
{ stream, mimetype, name });

// Invoke the handler now, if set
const handler = managedClient.deferredPipeStreamHandlers[name];
if (handler) {

// Handle the stream, and clear from the deferred streams
handler(stream, mimetype, name);
delete managedClient.deferredPipeStreams[name];
}
};

// Test for argument mutability whenever an argument value is
// received
client.onargv = function clientArgumentValueReceived(stream, mimetype, name) {
Expand Down Expand Up @@ -1004,6 +1076,72 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',

};


/**
* Register a handler that will be automatically invoked for any deferred
* pipe stream with the provided name, either when a pipe stream with a
* name matching a registered handler is received, or immediately when this
* function is called, if such a pipe stream has already been received.
*
* NOTE: Pipe streams are automatically deferred by the default onpipe
* implementation. To preserve this behavior when using a custom onpipe
* callback, make sure to defer to the default implementation as needed.
*
* @param {ManagedClient} managedClient
* The client for which the deferred pipe stream handler should be set.
*
* @param {String} name
* The name of the pipe stream that should be handeled by the provided
* handler. If another handler is already registered for this name, it
* will be replaced by the handler provided to this function.
*
* @param {Function} handler
* The handler that should handle any deferred pipe stream with the
* provided name. This function must take the same arguments as the
* standard onpipe handler - namely, the stream itself, the mimetype,
* and the name.
*/
ManagedClient.registerDeferredPipeHandler = function registerDeferredPipeHandler(
managedClient, name, handler) {
managedClient.deferredPipeStreamHandlers[name] = handler;

// Invoke the handler now, if the pipestream has already been received
if (managedClient.deferredPipeStreams[name]) {

// Invoke the handler with the deferred pipe stream
var deferredStream = managedClient.deferredPipeStreams[name];
handler(deferredStream.stream,
deferredStream.mimetype,
deferredStream.name);

// Clean up the now-consumed pipe stream
delete managedClient.deferredPipeStreams[name];
}
};

/**
* Detach the provided deferred pipe stream handler, if it is currently
* registered for the provided pipe stream name.
*
* @param {String} name
* The name of the associated pipe stream for the handler that should
* be detached.
*
* @param {Function} handler
* The handler that should be detached.
*
* @param {ManagedClient} managedClient
* The client for which the deferred pipe stream handler should be
* detached.
*/
ManagedClient.detachDeferredPipeHandler = function detachDeferredPipeHandler(
managedClient, name, handler) {

// Remove the handler if found
if (managedClient.deferredPipeStreamHandlers[name] === handler)
delete managedClient.deferredPipeStreamHandlers[name];
};

return ManagedClient;

}]);
Loading