Skip to content

Commit

Permalink
GUACAMOLE-1974: Allow deferring received pipe streams for later consu…
Browse files Browse the repository at this point in the history
…mption by name-specific handlers.
  • Loading branch information
jmuehlner committed Oct 30, 2024
1 parent deb858a commit 2770ef3
Showing 1 changed file with 139 additions and 1 deletion.
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;

}]);

0 comments on commit 2770ef3

Please sign in to comment.