mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-08 06:01:22 +00:00
Merge pull request #159 from glyptodon/session-storage
GUAC-1161: Implement session-local storage.
This commit is contained in:
@@ -30,18 +30,34 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
|||||||
var ManagedClient = $injector.get('ManagedClient');
|
var ManagedClient = $injector.get('ManagedClient');
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $window = $injector.get('$window');
|
var $window = $injector.get('$window');
|
||||||
var $rootScope = $injector.get('$rootScope');
|
var sessionStorageFactory = $injector.get('sessionStorageFactory');
|
||||||
|
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of all active managed clients. Each key is the ID of the connection
|
* Getter/setter which retrieves or sets the map of all active managed
|
||||||
* used by that client.
|
* clients. Each key is the ID of the connection used by that client.
|
||||||
*
|
*
|
||||||
* @type Object.<String, ManagedClient>
|
* @type Function
|
||||||
*/
|
*/
|
||||||
service.managedClients = {};
|
var storedManagedClients = sessionStorageFactory.create({}, function destroyClientStorage() {
|
||||||
|
|
||||||
|
// Disconnect all clients when storage is destroyed
|
||||||
|
service.clear();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a map of all active managed clients. Each key is the ID of the
|
||||||
|
* connection used by that client.
|
||||||
|
*
|
||||||
|
* @returns {Object.<String, ManagedClient>}
|
||||||
|
* A map of all active managed clients.
|
||||||
|
*/
|
||||||
|
service.getManagedClients = function getManagedClients() {
|
||||||
|
return storedManagedClients();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the existing ManagedClient associated with the connection having
|
* Removes the existing ManagedClient associated with the connection having
|
||||||
@@ -55,13 +71,15 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
|||||||
* true if an existing client was removed, false otherwise.
|
* true if an existing client was removed, false otherwise.
|
||||||
*/
|
*/
|
||||||
service.removeManagedClient = function replaceManagedClient(id) {
|
service.removeManagedClient = function replaceManagedClient(id) {
|
||||||
|
|
||||||
|
var managedClients = storedManagedClients();
|
||||||
|
|
||||||
// Remove client if it exists
|
// Remove client if it exists
|
||||||
if (id in service.managedClients) {
|
if (id in managedClients) {
|
||||||
|
|
||||||
// Disconnect and remove
|
// Disconnect and remove
|
||||||
service.managedClients[id].client.disconnect();
|
managedClients[id].client.disconnect();
|
||||||
delete service.managedClients[id];
|
delete managedClients[id];
|
||||||
|
|
||||||
// A client was removed
|
// A client was removed
|
||||||
return true;
|
return true;
|
||||||
@@ -96,7 +114,7 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
|||||||
service.removeManagedClient(id);
|
service.removeManagedClient(id);
|
||||||
|
|
||||||
// Set new client
|
// Set new client
|
||||||
return service.managedClients[id] = ManagedClient.getInstance(id, connectionParameters);
|
return storedManagedClients()[id] = ManagedClient.getInstance(id, connectionParameters);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,12 +137,14 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
|||||||
*/
|
*/
|
||||||
service.getManagedClient = function getManagedClient(id, connectionParameters) {
|
service.getManagedClient = function getManagedClient(id, connectionParameters) {
|
||||||
|
|
||||||
|
var managedClients = storedManagedClients();
|
||||||
|
|
||||||
// Create new managed client if it doesn't already exist
|
// Create new managed client if it doesn't already exist
|
||||||
if (!(id in service.managedClients))
|
if (!(id in managedClients))
|
||||||
service.managedClients[id] = ManagedClient.getInstance(id, connectionParameters);
|
managedClients[id] = ManagedClient.getInstance(id, connectionParameters);
|
||||||
|
|
||||||
// Return existing client
|
// Return existing client
|
||||||
return service.managedClients[id];
|
return managedClients[id];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -133,23 +153,20 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
|||||||
*/
|
*/
|
||||||
service.clear = function clear() {
|
service.clear = function clear() {
|
||||||
|
|
||||||
|
var managedClients = storedManagedClients();
|
||||||
|
|
||||||
// Disconnect each managed client
|
// Disconnect each managed client
|
||||||
for (var id in service.managedClients)
|
for (var id in managedClients)
|
||||||
service.managedClients[id].client.disconnect();
|
managedClients[id].client.disconnect();
|
||||||
|
|
||||||
// Clear managed clients
|
// Clear managed clients
|
||||||
service.managedClients = {};
|
storedManagedClients({});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Disconnect all clients when window is unloaded
|
// Disconnect all clients when window is unloaded
|
||||||
$window.addEventListener('unload', service.clear);
|
$window.addEventListener('unload', service.clear);
|
||||||
|
|
||||||
// Clear clients on logout
|
|
||||||
$rootScope.$on('guacLogout', function handleLogout() {
|
|
||||||
service.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
@@ -137,11 +137,13 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
|||||||
if (rootGroup)
|
if (rootGroup)
|
||||||
addVisibleConnectionGroup(rootGroup);
|
addVisibleConnectionGroup(rootGroup);
|
||||||
|
|
||||||
|
var managedClients = guacClientManager.getManagedClients();
|
||||||
|
|
||||||
// Add all active connections
|
// Add all active connections
|
||||||
for (var id in guacClientManager.managedClients) {
|
for (var id in managedClients) {
|
||||||
|
|
||||||
// Get corresponding managed client
|
// Get corresponding managed client
|
||||||
var client = guacClientManager.managedClients[id];
|
var client = managedClients[id];
|
||||||
|
|
||||||
// Add active connections for clients with associated visible objects
|
// Add active connections for clients with associated visible objects
|
||||||
if (id in visibleObjects) {
|
if (id in visibleObjects) {
|
||||||
@@ -157,7 +159,7 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
|||||||
guacHistory.recentConnections.forEach(function addRecentConnection(historyEntry) {
|
guacHistory.recentConnections.forEach(function addRecentConnection(historyEntry) {
|
||||||
|
|
||||||
// Add recent connections for history entries with associated visible objects
|
// Add recent connections for history entries with associated visible objects
|
||||||
if (historyEntry.id in visibleObjects && !(historyEntry.id in guacClientManager.managedClients)) {
|
if (historyEntry.id in visibleObjects && !(historyEntry.id in managedClients)) {
|
||||||
|
|
||||||
var object = visibleObjects[historyEntry.id];
|
var object = visibleObjects[historyEntry.id];
|
||||||
$scope.recentConnections.push(new RecentConnection(object.name, historyEntry));
|
$scope.recentConnections.push(new RecentConnection(object.name, historyEntry));
|
||||||
|
@@ -23,4 +23,6 @@
|
|||||||
/**
|
/**
|
||||||
* The module for code used to display arbitrary notifications.
|
* The module for code used to display arbitrary notifications.
|
||||||
*/
|
*/
|
||||||
angular.module('notification', []);
|
angular.module('notification', [
|
||||||
|
'storage'
|
||||||
|
]);
|
||||||
|
@@ -23,34 +23,33 @@
|
|||||||
/**
|
/**
|
||||||
* Service for displaying notifications and modal status dialogs.
|
* Service for displaying notifications and modal status dialogs.
|
||||||
*/
|
*/
|
||||||
angular.module('notification').factory('guacNotification', ['$rootScope',
|
angular.module('notification').factory('guacNotification', ['$injector',
|
||||||
function guacNotification($rootScope) {
|
function guacNotification($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $rootScope = $injector.get('$rootScope');
|
||||||
|
var sessionStorageFactory = $injector.get('sessionStorageFactory');
|
||||||
|
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current status notification, or false if no status is currently
|
* Getter/setter which retrieves or sets the current status notification,
|
||||||
* shown.
|
* which may simply be false if no status is currently shown.
|
||||||
|
*
|
||||||
|
* @type Function
|
||||||
|
*/
|
||||||
|
var storedStatus = sessionStorageFactory.create(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current status notification, which may simply be false if
|
||||||
|
* no status is currently shown.
|
||||||
*
|
*
|
||||||
* @type Notification|Boolean
|
* @type Notification|Boolean
|
||||||
*/
|
*/
|
||||||
service.status = false;
|
service.getStatus = function getStatus() {
|
||||||
|
return storedStatus();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* All currently-visible notifications.
|
|
||||||
*
|
|
||||||
* @type Notification[]
|
|
||||||
*/
|
|
||||||
service.notifications = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ID of the most recently shown notification, or 0 if no notifications
|
|
||||||
* have yet been shown.
|
|
||||||
*
|
|
||||||
* @type Number
|
|
||||||
*/
|
|
||||||
var notificationUniqueID = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows or hides the given notification as a modal status. If a status
|
* Shows or hides the given notification as a modal status. If a status
|
||||||
* notification is currently shown, no further statuses will be shown
|
* notification is currently shown, no further statuses will be shown
|
||||||
@@ -77,59 +76,10 @@ angular.module('notification').factory('guacNotification', ['$rootScope',
|
|||||||
* guacNotification.showStatus(false);
|
* guacNotification.showStatus(false);
|
||||||
*/
|
*/
|
||||||
service.showStatus = function showStatus(status) {
|
service.showStatus = function showStatus(status) {
|
||||||
if (!service.status || !status)
|
if (!storedStatus() || !status)
|
||||||
service.status = status;
|
storedStatus(status);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a notification to the the list of notifications shown.
|
|
||||||
*
|
|
||||||
* @param {Notification|Object} notification
|
|
||||||
* The notification to add.
|
|
||||||
*
|
|
||||||
* @returns {Number}
|
|
||||||
* A unique ID for the notification that's just been added.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* var id = guacNotification.addNotification({
|
|
||||||
* 'title' : 'Download',
|
|
||||||
* 'text' : 'You have a file ready for download!',
|
|
||||||
* 'actions' : {
|
|
||||||
* 'name' : 'download',
|
|
||||||
* 'callback' : function () {
|
|
||||||
* // download the file and remove the notification here
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
service.addNotification = function addNotification(notification) {
|
|
||||||
var id = ++notificationUniqueID;
|
|
||||||
|
|
||||||
service.notifications.push({
|
|
||||||
notification : notification,
|
|
||||||
id : id
|
|
||||||
});
|
|
||||||
|
|
||||||
return id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a notification by unique ID.
|
|
||||||
*
|
|
||||||
* @param {Number} id
|
|
||||||
* The unique ID of the notification to remove. This ID is retrieved
|
|
||||||
* from the initial call to addNotification.
|
|
||||||
*/
|
|
||||||
service.removeNotification = function removeNotification(id) {
|
|
||||||
for (var i = 0; i < service.notifications.length; i++) {
|
|
||||||
if (service.notifications[i].id === id) {
|
|
||||||
service.notifications.splice(i, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hide status upon navigation
|
// Hide status upon navigation
|
||||||
$rootScope.$on('$routeChangeSuccess', function() {
|
$rootScope.$on('$routeChangeSuccess', function() {
|
||||||
service.showStatus(false);
|
service.showStatus(false);
|
||||||
|
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for session-local storage. Creating session-local storage creates a
|
||||||
|
* getter/setter with semantics tied to the user's session. If a user is logged
|
||||||
|
* in, the storage is consistent. If the user logs out, the storage will not
|
||||||
|
* persist new values, and attempts to retrieve the existing value will result
|
||||||
|
* only in the default value.
|
||||||
|
*/
|
||||||
|
angular.module('storage').factory('sessionStorageFactory', ['$injector', function sessionStorageFactory($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $rootScope = $injector.get('$rootScope');
|
||||||
|
var authenticationService = $injector.get('authenticationService');
|
||||||
|
|
||||||
|
var service = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates session-local storage that uses the provided default value or
|
||||||
|
* getter to obtain new values as necessary. Beware that if the default is
|
||||||
|
* an object, the resulting getter provide deep copies for new values.
|
||||||
|
*
|
||||||
|
* @param {Function|*} [template]
|
||||||
|
* The default value for new users, or a getter which returns a newly-
|
||||||
|
* created default value.
|
||||||
|
*
|
||||||
|
* @param {Function} [destructor]
|
||||||
|
* Function which will be called just before the stored value is
|
||||||
|
* destroyed on logout, if a value is stored.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
* A getter/setter which returns or sets the current value of the new
|
||||||
|
* session-local storage. Newly-set values will only persist of the
|
||||||
|
* user is actually logged in.
|
||||||
|
*/
|
||||||
|
service.create = function create(template, destructor) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether new values may be stored and retrieved.
|
||||||
|
*
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
var enabled = !!authenticationService.getCurrentToken();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter which returns the default value for this storage.
|
||||||
|
*
|
||||||
|
* @type Function
|
||||||
|
*/
|
||||||
|
var getter;
|
||||||
|
|
||||||
|
// If getter provided, use that
|
||||||
|
if (typeof template === 'function')
|
||||||
|
getter = template;
|
||||||
|
|
||||||
|
// Otherwise, always create a deep copy
|
||||||
|
else
|
||||||
|
getter = function getCopy() {
|
||||||
|
return angular.copy(template);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current value of this storage, or undefined if not yet set.
|
||||||
|
*/
|
||||||
|
var value = undefined;
|
||||||
|
|
||||||
|
// Reset value and allow storage when the user is logged in
|
||||||
|
$rootScope.$on('guacLogin', function userLoggedIn() {
|
||||||
|
enabled = true;
|
||||||
|
value = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset value and disallow storage when the user is logged out
|
||||||
|
$rootScope.$on('guacLogout', function userLoggedOut() {
|
||||||
|
|
||||||
|
// Call destructor before storage is teared down
|
||||||
|
if (angular.isDefined(value) && destructor)
|
||||||
|
destructor(value);
|
||||||
|
|
||||||
|
// Destroy storage
|
||||||
|
enabled = false;
|
||||||
|
value = undefined;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return getter/setter for value
|
||||||
|
return function sessionLocalGetterSetter(newValue) {
|
||||||
|
|
||||||
|
// Only actually store/retrieve values if enabled
|
||||||
|
if (enabled) {
|
||||||
|
|
||||||
|
// Set value if provided
|
||||||
|
if (angular.isDefined(newValue))
|
||||||
|
value = newValue;
|
||||||
|
|
||||||
|
// Obtain new value if unset
|
||||||
|
if (!angular.isDefined(value))
|
||||||
|
value = getter();
|
||||||
|
|
||||||
|
// Return current value
|
||||||
|
return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, just pretend to store/retrieve
|
||||||
|
return angular.isDefined(newValue) ? newValue : getter();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
}]);
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -20,30 +20,9 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#notificationArea {
|
/**
|
||||||
position: fixed;
|
* Module which provides generic storage services.
|
||||||
right: 0.5em;
|
*/
|
||||||
bottom: 0.5em;
|
angular.module('storage', [
|
||||||
max-width: 25%;
|
'auth'
|
||||||
width: 2in;
|
]);
|
||||||
}
|
|
||||||
|
|
||||||
#notificationArea .notification {
|
|
||||||
font-size: 0.7em;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#notificationArea .notification .text {
|
|
||||||
width: 100%;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
#notificationArea .notification.error .text {
|
|
||||||
white-space: normal;
|
|
||||||
text-overflow: clip;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
@@ -38,22 +38,15 @@ THE SOFTWARE.
|
|||||||
<div ng-if="!expectedCredentials">
|
<div ng-if="!expectedCredentials">
|
||||||
|
|
||||||
<!-- Global status/error dialog -->
|
<!-- Global status/error dialog -->
|
||||||
<div ng-class="{shown: guacNotification.status}" class="status-outer">
|
<div ng-class="{shown: guacNotification.getStatus()}" class="status-outer">
|
||||||
<div class="status-middle">
|
<div class="status-middle">
|
||||||
<guac-notification notification="guacNotification.status"></guac-notification>
|
<guac-notification notification="guacNotification.getStatus()"></guac-notification>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="content" ng-view>
|
<div id="content" ng-view>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Notification area -->
|
|
||||||
<div id="notificationArea">
|
|
||||||
<div ng-repeat="wrapper in guacNotification.notifications">
|
|
||||||
<guac-notification notification="wrapper.notification"></guac-notification>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Login screen for logged-out users -->
|
<!-- Login screen for logged-out users -->
|
||||||
|
Reference in New Issue
Block a user