[X2Go-Commits] python-x2go.git - build-baikal (branch) updated: 35ec0740ece713767617c85c90c32c044dd23338

X2Go dev team git-admin at x2go.org
Wed Jan 8 15:29:19 CET 2014


The branch, build-baikal has been updated
       via  35ec0740ece713767617c85c90c32c044dd23338 (commit)
      from  e3fe57d1ad10f04c05565d3dbb712bc1d3f0caf5 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 x2go/backends/control/stdout.py         |   80 ++++++----------
 x2go/backends/profiles/sessions_file.py |   21 ----
 x2go/backends/terminal/stdout.py        |   20 ++--
 x2go/cache.py                           |   95 ++++++++++---------
 x2go/cleanup.py                         |   22 ++---
 x2go/client.py                          |  158 +++++++++++++++++++++++--------
 x2go/defaults.py                        |    3 +-
 x2go/guardian.py                        |   23 ++---
 x2go/registry.py                        |   66 ++++++++++++-
 x2go/session.py                         |   33 ++++---
 x2go/utils.py                           |    1 -
 x2go/x2go_exceptions.py                 |    5 +-
 12 files changed, 308 insertions(+), 219 deletions(-)

The diff of changes is:
diff --git a/x2go/backends/control/stdout.py b/x2go/backends/control/stdout.py
index 42ae7c9..088b48d 100644
--- a/x2go/backends/control/stdout.py
+++ b/x2go/backends/control/stdout.py
@@ -37,7 +37,6 @@ import x2go.log as log
 import x2go.utils as utils
 import x2go.x2go_exceptions as x2go_exceptions
 import x2go.defaults as defaults
-import x2go.cache as cache
 
 from x2go.backends.terminal import X2goTerminalSession as _X2goTerminalSession
 from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo
@@ -56,13 +55,13 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
     @type loglevel: int
 
     """
+    associated_terminals = None
+
     def __init__(self,
                  terminal_backend=_X2goTerminalSession,
                  info_backend=_X2goServerSessionInfo,
                  list_backend=_X2goServerSessionList,
                  proxy_backend=_X2goProxy,
-                 use_listsessions_cache=True,
-                 controlled_session=None,
                  logger=None, loglevel=log.loglevel_DEFAULT,
                  *args, **kwargs):
         """\
@@ -73,28 +72,21 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         """
         self.associated_terminals = {}
         self.terminated_terminals = []
-        self.controlled_sessions = {}
 
         self._session_auth_rsakey = None
         self._remote_home = None
         self._remote_group = {}
 
-        self.x2go_listsessions_cache = None
-
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
         else:
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
-        if controlled_session is not None:
-            self.controlled_sessions[controlled_session._X2goSession__get_uuid()] = controlled_session
-
         self._terminal_backend = terminal_backend
         self._info_backend = info_backend
         self._list_backend = list_backend
         self._proxy_backend = proxy_backend
-        self.use_listsessions_cache = use_listsessions_cache
         paramiko.SSHClient.__init__(self, *args, **kwargs)
 
     def __del__(self):
@@ -131,10 +123,10 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
                 self.logger('executing command on X2go server: %s' % cmd, loglevel)
                 return self.exec_command(cmd, **kwargs)
             except AttributeError:
-                raise x2go_exceptions.X2goSessionException('a Paramiko/SSH control session has died')
+                raise x2go_exceptions.X2goControlSessionException('a Paramiko/SSH control session has died')
 
         else:
-            raise x2go_exceptions.X2goSessionException('the Paramiko/SSH client is not connected')
+            raise x2go_exceptions.X2goControlSessionException('the Paramiko/SSH client is not connected')
 
     @property
     def _x2go_remote_home(self):
@@ -276,10 +268,6 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         ssh_transport._x2go_session_marker = True
         self._session_password = password
 
-        if self.use_listsessions_cache:
-            self.x2go_listsessions_cache = cache.X2goListSessionsCache(self, logger=self.logger)
-            self.x2go_listsessions_cache.start()
-
         return (self.get_transport() is not None)
 
     def disconnect(self):
@@ -287,33 +275,34 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         STILL UNDOCUMENTED
 
         """
-        if self.x2go_listsessions_cache is not None:
-            self.x2go_listsessions_cache.stop_thread()
-            del self.x2go_listsessions_cache
-            self.x2go_listsessions_cache = None
-
-        t_names = self.associated_terminals.keys()
-        for  t_obj in self.associated_terminals.values():
-            try:
-                t_obj.suspend()
-            except x2go_exceptions.X2goSessionException:
-                pass
-            del t_obj
-        for t_name in t_names:
-            del self.associated_terminals[t_name]
+        if self.associated_terminals is not None:
+            t_names = self.associated_terminals.keys()
+            for  t_obj in self.associated_terminals.values():
+                try:
+                    t_obj.suspend()
+                except x2go_exceptions.X2goTerminalSessionException:
+                    pass
+                del t_obj
+            for t_name in t_names:
+                del self.associated_terminals[t_name]
 
         self._remote_home = None
         self._remote_group = {}
 
         self._session_auth_rsakey = None
-        if self.get_transport() is not None:
-            self.get_transport().close()
+
+        try:
+            if self.get_transport() is not None:
+                self.get_transport().close()
+        except AttributeError:
+            # if the Paramiko _transport object has not yet been initialized, ignore it
+            pass
 
     def is_alive(self):
         try:
             self._x2go_exec_command('echo', loglevel=log.loglevel_DEBUG)
             return True
-        except x2go_exceptions.X2goSessionException:
+        except x2go_exceptions.X2goControlSessionException:
             return False
 
     def start(self, **kwargs):
@@ -342,7 +331,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group x2gousers' % self.get_transport().get_username())
 
         if session_name is not None:
-            session_info = self.list_sessions(refresh_cache=True)[session_name]
+            session_info = self.list_sessions()[session_name]
         else:
             session_info = None
 
@@ -379,7 +368,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
         return _terminal or None
 
-    def list_sessions(self, raw=False, no_cache=False, refresh_cache=False):
+    def list_sessions(self, raw=False):
         """\
         List all sessions of current user on the connected server.
 
@@ -396,25 +385,18 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         if raw:
             return stdout.read(), stderr.read()
 
-        elif no_cache or refresh_cache or (self.use_listsessions_cache is False) or (self.x2go_listsessions_cache is None):
+        else:
 
             try:
                 (stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
 
                 _stdout_read = stdout.read()
                 _listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
-                if refresh_cache and self.x2go_listsessions_cache is not None:
-                    self.x2go_listsessions_cache.update_session_list(session_list=_listsessions)
 
                 return _listsessions
 
-            except X2goSessionException, e:
-                self.logger('encountered X2goSessionsException: %s' % str(e), loglevel=log.loglevel_ERROR)
-                self._X2goSessions__disconnect()
-
-        else:
-
-            return self.x2go_listsessions_cache.list_sessions()
+            except X2goSessionControlException, e:
+                self.logger('encountered X2goSessionsControlException: %s' % str(e), loglevel=log.loglevel_ERROR)
 
     def clean_sessions(self):
         """\
@@ -422,7 +404,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         connected user on the remote X2go server and terminate them.
 
         """
-        session_infos = self.list_sessions(refresh_cache=True)
+        session_infos = self.list_sessions()
         for session_info in session_infos.values():
             self.terminate(session_name=session_info)
 
@@ -452,7 +434,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         @rtype: C{bool}
 
         """
-        session_infos = self.list_sessions(refresh_cache=True)
+        session_infos = self.list_sessions()
         if session_name in session_infos.keys():
             return session_infos[session_name].is_running()
         return False
@@ -466,7 +448,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         @rtype: C{bool}
 
         """
-        session_infos = self.list_sessions(refresh_cache=True)
+        session_infos = self.list_sessions()
         if session_name in session_infos.keys():
             return session_infos[session_name].is_suspended()
         return False
@@ -483,7 +465,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         @rtype: C{bool}
 
         """
-        session_infos = self.list_sessions(refresh_cache=True)
+        session_infos = self.list_sessions()
 
         if session_name not in session_infos.keys():
             if session_name in self.terminated_terminals:
diff --git a/x2go/backends/profiles/sessions_file.py b/x2go/backends/profiles/sessions_file.py
index 4d1644b..fe2c457 100644
--- a/x2go/backends/profiles/sessions_file.py
+++ b/x2go/backends/profiles/sessions_file.py
@@ -180,27 +180,6 @@ class X2goSessionProfilesFILE(inifiles.X2goIniFile):
         self.write_user_config = True
         self.writeIniFile()
 
-    def has_default_profiles(self):
-        """\
-        STILL UNDOCUMENTED
-
-        """
-        return self.get_default_profiles() and True or False
-
-    def get_default_profiles(self):
-        """\
-        Find profiles marked as default profiles. If appropriate, default
-        profiles may be started immediately on client startup.
-
-        """
-        _default_profiles = []
-        for profile_name in self.profile_names:
-            _profile_id = self.to_profile_id(profile_name)
-            _profile_config = self.get_profile_config(profile_name)
-            if _profile_config['default']:
-                _default_profiles.append(_profile_id)
-        return _default_profiles
-
     def check_profile_id_or_name(self, profile_id_or_name):
         """\
         STILL UNDOCUMENTED
diff --git a/x2go/backends/terminal/stdout.py b/x2go/backends/terminal/stdout.py
index 5e0d259..b992f0c 100644
--- a/x2go/backends/terminal/stdout.py
+++ b/x2go/backends/terminal/stdout.py
@@ -44,7 +44,6 @@ import x2go.log as log
 import x2go.defaults as defaults
 import x2go.utils as utils
 import x2go.x2go_exceptions as x2go_exceptions
-import x2go.guardian as guardian
 
 from x2go.cleanup import x2go_cleanup 
 
@@ -212,7 +211,7 @@ class X2goTerminalSessionSTDOUT(object):
         self.proxy = None
         self.proxy_subprocess = None
 
-        self.guardian_thread = None
+        self.active_threads = []
         self.reverse_tunnels = {}
 
         self.print_queue = None
@@ -253,15 +252,10 @@ class X2goTerminalSessionSTDOUT(object):
             if self.session_info.name:
                 self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name)
             else:
-                raise X2goSessionException('no valid session info availble')
+                raise X2goTerminalSessionException('no valid session info availble')
         else:
             self.session_info = info_backend()
 
-        # each terminal session has its own guardian
-        self.guardian_thread = guardian.X2goSessionGuardian(self, logger=self.logger)
-        self.guardian_thread.start()
-
-
     def __del__(self):
         self._x2go_tidy_up()
 
@@ -361,7 +355,7 @@ class X2goTerminalSessionSTDOUT(object):
             if _tunnel is not None:
                 self.reverse_tunnels[self.session_info.name]['snd'] = (self.session_info.snd_port, _tunnel)
                 _tunnel.start()
-                self.guardian_thread.active_threads.append(_tunnel)
+                self.active_threads.append(_tunnel)
 
         else:
             # tunnel has already been started and might simply need a resume call
@@ -385,7 +379,7 @@ class X2goTerminalSessionSTDOUT(object):
             if _tunnel is not None:
                 self.reverse_tunnels[self.session_info.name]['sshfs'] = (self.session_info.sshfs_port, _tunnel)
                 _tunnel.start()
-                self.guardian_thread.active_threads.append(_tunnel)
+                self.active_threads.append(_tunnel)
 
         else:
             # tunnel has already been started and might simply need a resume call
@@ -430,7 +424,7 @@ class X2goTerminalSessionSTDOUT(object):
                                                    logger=self.logger,
                                                   )
         self.print_queue.start()
-        self.guardian_thread.active_threads.append(self.print_queue)
+        self.active_threads.append(self.print_queue)
 
     def set_print_action(self, print_action, **kwargs):
         """\
@@ -464,7 +458,7 @@ class X2goTerminalSessionSTDOUT(object):
 
         """
         if self.session_info.username not in self.control_session._x2go_remote_group('fuse'):
-            raise x2go_exceptions.X2goSessionException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
+            raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
 
         if folder_name is None:
             self.logger('no folder name given...', log.loglevel_WARN)
@@ -647,7 +641,7 @@ class X2goTerminalSessionSTDOUT(object):
         # set up SSH tunnel for X11 graphical elements
         self.proxy = self.proxy_class(session_info=self.session_info, ssh_transport=self.control_session.get_transport(), logger=self.logger)
         self.proxy_subprocess = self.proxy.start_proxy()
-        self.guardian_thread.active_threads.append(self.proxy)
+        self.active_threads.append(self.proxy)
 
         return self.ok()
 
diff --git a/x2go/cache.py b/x2go/cache.py
index b1e8e89..647d000 100644
--- a/x2go/cache.py
+++ b/x2go/cache.py
@@ -24,35 +24,34 @@ X2goListSessionCache class - caching X2go session information.
 __NAME__ = 'x2gocache-pylib'
 
 # modules
-import gevent
-import threading
 import copy
 
 # Python X2go modules
 import log
 import x2go_exceptions
 
-class X2goListSessionsCache(threading.Thread):
+class X2goListSessionsCache(object):
     """\
     STILL UNDOCUMENTED
 
     """
+    x2go_listsessions_cache = {}
 
-    def __init__(self, control_session, refresh_interval=5, logger=None, loglevel=log.loglevel_DEFAULT):
+    def __init__(self, client, refresh_interval=5, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
-        @param control: the L{X2goControlSession} that uses this L{X2goListSessionsCache}
-        @type control: C{instance}
+        @param client: the L{X2goClient} instance that uses this L{X2goListSessionsCache}
+        @type client: C{instance}
         @param refresh_interval: refresh interval of the list sessions cache in seconds
         @type refresh_interval: C{int}
-        @param logger: you can pass an L{X2goLogger} object to the L{X2goSessionGuardian} constructor
+        @param logger: you can pass an L{X2goLogger} object to the L{X2goListSessionsCache} constructor
         @type logger: C{instance}
         @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
             constructed with the given loglevel
         @type loglevel: C{int}
 
         """
-        self.x2go_listsessions_cache = None
-        self.last_listsessions_cache = None
+        self.x2go_listsessions_cache = {}
+        self.last_listsessions_cache = {}
 
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
@@ -60,57 +59,65 @@ class X2goListSessionsCache(threading.Thread):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
-        self.control_session = control_session
-        self.last_sessionlist = None
+        self.client = client
         self.refresh_interval = refresh_interval
-        threading.Thread.__init__(self, target=self.refresh_cache)
-        self.daemon = True
 
-    def refresh_cache(self):
+    def check_cache(self, seconds=None):
+
+        if seconds and (seconds % self.refresh_interval != 0):
+            return
+
+        for profile_name in self.x2go_listsessions_cache.keys():
+            if profile_name not in [ self.client.to_profile_name(p_id) for p_id in self.client.connected_profiles ]:
+                del self.x2go_listsessions_cache[profile_name]
+
+    def update_all(self, seconds=None):
         """\
-        The handler of this L{X2goListSessionsCache} thread.
+        Update L{X2goListSessionsCache} for all connected profiles.
+
+        @param profile_name: name of profile to update
+        @type profile_name: C{str}
 
         """
-        seconds = 0
-        self._keepalive = True
-        while self._keepalive:
-            gevent.sleep(1)
-            seconds += 1
-            if seconds % self.refresh_interval == 0:
-                self.list_listsessions_cache = copy.deepcopy(self.x2go_listsessions_cache)
-                self.update_session_list()
-
-    def update_session_list(self, session_list=None):
+        if seconds and (seconds % self.refresh_interval != 0):
+            return
+
+        for profile_name in self.client.connected_profiles:
+            self.update(profile_name, seconds=seconds)
+
+        self.check_cache(seconds=seconds)
+
+    def update(self, profile_name, seconds=None):
         """\
-        Retrieve a recent session list either from the control session's C{list_sessions()}
-        method or as an argument.
+        Update the L{X2goListSessionsCache} for profile C{profile_name}.
 
-        @param session_list: an L{X2goServerSessionList} backend instance
-        @type session_list C{instance}
+        @param profile_name: name of profile to update
+        @type profile_name: C{str}
 
         """
-        if session_list is None:
-            try:
-                self.x2go_listsessions_cache = self.control_session.list_sessions(no_cache=True)
-            except x2go_exceptions.X2goSessionException:
-                for s in self.control_session.controlled_sessions.values():
-                    s.__hook_session_has_died()
-                    s._X2goSession__disconnect()
+        if seconds and (seconds % self.refresh_interval != 0):
+            return
+
+        self.last_listsessions_cache = copy.deepcopy(self.x2go_listsessions_cache)
+        control_session = self.client.client_control_session_of_name(profile_name)
+        if control_session is not None:
+            self.x2go_listsessions_cache[profile_name] = control_session.list_sessions()
         else:
-            self.x2go_listsessions_cache = session_list
+            del self.x2go_listsessions_cache[profile_name]
 
-    def list_sessions(self):
+    def list_sessions(self, session_uuid):
         """\
         Retrieve the current cache content of L{X2goListSessionsCache}.
 
         """
-        return self.x2go_listsessions_cache
+        profile_name = self.client.get_session_profile_name(session_uuid)
+        return self.x2go_listsessions_cache[profile_name]
 
-    def stop_thread(self):
+    def is_cached(self, session_uuid=None, profile_name=None):
         """\
-        Stop this L{X2goListSessionsCache} thread.
+        Retrieve the current cache content of L{X2goListSessionsCache}.
 
         """
-        self._keepalive = False
-
-
+        if profile_name is None and session_uuid:
+            profile_name = self.client.get_session_profile_name(session_uuid)
+        return self.x2go_listsessions_cache.has_key(profile_name)
diff --git a/x2go/cleanup.py b/x2go/cleanup.py
index 04949df..a6f3219 100644
--- a/x2go/cleanup.py
+++ b/x2go/cleanup.py
@@ -27,7 +27,7 @@ import guardian
 import rforward
 
 
-def x2go_cleanup(e=None, terminal_session=None, threads=[]):
+def x2go_cleanup(e=None, threads=None):
     """\
     For every Python X2go application you write, please make sure to 
     capture the KeyboardInterrupt and the SystemExit exceptions and 
@@ -49,33 +49,27 @@ def x2go_cleanup(e=None, terminal_session=None, threads=[]):
     @param e: if L{x2go_cleanup} got called as we caught an exception this can be the C{Exception} that
         we might process at the end of the clean-up (or if clean-up failed or was not appropriate)
     @type e: C{exception}
-    @param terminal_session: an L{X2goSession} object
-    @type terminal_session: C{instance}
     @param threads: a list of threads to clean up
     @type threads: C{list}
 
     """
-    if terminal_session is None:
-        active_threads = threading.enumerate()
+    if threads is None:
+        threads = threading.enumerate()
     else:
-        terminal_session.logger('cleaning up threads of terminal session: %s' % terminal_session.session_info.name)
-        active_threads = threads
+        threads = threads
 
     # stop X2go reverse forwarding tunnels
-    for t in active_threads:
+    for t in threads:
         if type(t) == rforward.X2goRevFwTunnel:
             t.stop_thread()
+            del t
 
     # stop X2go paramiko transports used by X2goTerminalSession objects
-    for t in active_threads:
+    for t in threads:
         if type(t) == paramiko.Transport:
             if hasattr(t, '_x2go_session_marker'):
                 t.stop_thread()
-
-    # stop the X2goGuardian threads (one per X2goSession
-    for t in active_threads:
-        if type(t) == guardian.X2goSessionGuardian:
-            t.stop_thread()
+                del t
 
     if e is not None:
         raise e
diff --git a/x2go/client.py b/x2go/client.py
index c1ea7b2..be1ae0e 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -126,6 +126,8 @@ from settings import X2goClientSettings
 from printing import X2goClientPrinting
 from registry import X2goSessionRegistry
 from guardian import X2goSessionGuardian
+from cache import X2goListSessionsCache
+import x2go_exceptions
 import log
 import utils
 
@@ -146,7 +148,7 @@ class X2goClient(object):
     session object etc.) and connected to it (authentication). For these two steps
     use these methods: L{X2goClient.register_session()} and L{X2goClient.connect_session()}.
     """
-    def __init__(self, logger=None, loglevel=log.loglevel_DEFAULT):
+    def __init__(self, use_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         @param logger: you can pass an L{X2goLogger} object to the
             L{X2goClient} constructor
@@ -156,6 +158,8 @@ class X2goClient(object):
         @type loglevel: C{int}
 
         """
+        self.listsessions_cache = None
+
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
         else:
@@ -166,9 +170,22 @@ class X2goClient(object):
 
         self.session_profiles = X2goSessionProfiles(logger=self.logger)
         self.session_registry = X2goSessionRegistry(logger=self.logger)
+        self.session_guardian = X2goSessionGuardian(self, enable_cache=use_cache, logger=self.logger)
+        if use_cache:
+            self.listsessions_cache = X2goListSessionsCache(self, logger=self.logger)
         self.client_settings = X2goClientSettings(logger=self.logger)
         self.client_printing = X2goClientPrinting(logger=self.logger)
 
+        self.use_cache = use_cache
+
+    # user hooks for detecting/notifying what happened with this session 
+    def HOOK_on_control_session_death(self, profile_name):
+        self.logger('the control session of profile %s has died unexpectedly' % profile_name)
+    def HOOK_on_session_got_suspended_from_within(self, session_uuid):
+        self.logger('session %s has been suspended from within the application' % self.session_registry(session_uuid).get_session_name())
+    def HOOK_on_session_got_terminated_from_within(self, session_uuid):
+        self.logger('session %s has been terminated from within the application' % self.session_registry(session_uuid).get_session_name())
+
     def __get_client_username(self):
         """\
         Query the local user's username (i.e. the user running the X2go client).
@@ -180,19 +197,6 @@ class X2goClient(object):
         return _CURRENT_LOCAL_USER
     get_client_username = __get_client_username
 
-    def __is_valid_username(self):
-        """\
-        Check if user is allowed to start an X2go session on a remote server.
-
-        @return User allowed to start a session?
-        @rtype: C{str}
-
-        """
-        return _CURRENT_LOCAL_USER
-    get_client_username = __get_client_username
-
-
-
     def register_all_session_profiles(self, return_objects=False):
         """\
         Register all session profiles found in the C{sessions} configuration file 
@@ -328,7 +332,18 @@ class X2goClient(object):
     __register_session = register_session
 
     ###
-    ### WRAPPER METHODS FOR X2goRegisteredSession objects
+    ### WRAPPER METHODS FOR X2goSessionRegistry objects
+    ###
+
+    def get_session_summary(self, session_uuid):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.session_registry.session_summary(session_uuid)
+
+    ###
+    ### WRAPPER METHODS FOR X2goSession objects
     ###
 
     def get_session_username(self, session_uuid):
@@ -388,27 +403,6 @@ class X2goClient(object):
     with_session = __get_session
     """Alias for L{get_session()}."""
 
-    def get_registered_session(self, session_uuid):
-        """\
-        Retrieve the complete L{X2goRegisteredSession} object that has been 
-        registered under the given session registry hash.
-
-        L{X2goRegisteredSession} is one of Python X2go's public API classes 
-        and may safely be used in user applications to operate on individual 
-        sessions.
-
-        @param session_uuid: the X2go session's UUID registry hash
-        @type session_uuid: C{str}
-
-        @return: the L{X2goRegisteredSession} instance
-        @rtype: obj
-
-        """
-        return self.session_registry(session_uuid)
-    __get_registered_session = get_registered_session
-    with_registered_session = __get_registered_session
-    """Alias for L{get_registered_session()}."""
-
     def get_session_name(self, session_uuid):
         """\
         Retrieve the server-side X2go session name for the session that has
@@ -853,6 +847,23 @@ class X2goClient(object):
         return self.session_registry.registered_sessions
     __client_registered_sessions = client_registered_sessions
 
+    @property
+    def client_control_sessions(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.session_registry.control_sessions
+    __client_control_sessions = client_control_sessions
+
+    def client_control_session_of_name(self, profile_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.session_registry.control_session_of_name(profile_name)
+    __client_control_session_of_name = client_control_session_of_name
+
     def client_registered_sessions_of_name(self, profile_name):
         """\
         STILL UNDOCUMENTED
@@ -890,7 +901,7 @@ class X2goClient(object):
 
         """
         if self._X2goClient__is_session_connected(session_uuid):
-            session_list = self._X2goClient__list_sessions(session_uuid, refresh_cache=True)
+            session_list = self._X2goClient__list_sessions(session_uuid)
             return [ key for key in session_list.keys() if session_list[key].status == 'R' ]
         else:
             raise X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
@@ -919,7 +930,7 @@ class X2goClient(object):
 
         """
         if self._X2goClient__is_session_connected(session_uuid):
-            session_list = self._X2goClient__list_sessions(session_uuid, refresh_cache=True)
+            session_list = self._X2goClient__list_sessions(session_uuid)
             return [ key for key in session_list.keys() if session_list[key].status == 'S' ]
         else:
             raise X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
@@ -979,7 +990,18 @@ class X2goClient(object):
 
         """
         session = self.session_registry(session_uuid)
-        return session.list_sessions(no_cache=no_cache, refresh_cache=refresh_cache)
+
+        if not self.use_cache or no_cache:
+            return session.list_sessions()
+        elif refresh_cache:
+            self.update_cache_by_session_uuid(session_uuid)
+            return self.listsessions_cache.list_sessions(session_uuid)
+        else:
+            # if there is no cache for this session_uuid available, make sure the cache gets updated
+            # before reading from it...
+            if self.use_cache and (not self.listsessions_cache.is_cached(session_uuid=session_uuid)):
+                self.update_cache_by_session_uuid(session_uuid)
+            return self.listsessions_cache.list_sessions(session_uuid)
     __list_sessions = list_sessions
 
     ###
@@ -1066,7 +1088,7 @@ class X2goClient(object):
         @rtype: C{str}
 
         """
-        return self.session_profiles.get_profile_id(profile_name)
+        return self.session_profiles.to_profile_id(profile_name)
     __to_profile_id = to_profile_id
 
     def to_profile_name(self, profile_id):
@@ -1081,7 +1103,61 @@ class X2goClient(object):
         @rtype: C{str}
 
         """
-        return self.session_profiles.get_profile_name(profile_id)
+        return self.session_profiles.to_profile_name(profile_id)
     __to_profile_name = to_profile_name
 
+    @property
+    def connected_profiles(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.session_registry.connected_profiles
+    __connected_profiles = connected_profiles
+
+    def disconnect_profile(self, profile_name):
+        """\
+        Disconnect all L{X2goSession} instances that relate to C{profile_name} by closing down their
+        Paramiko/SSH Transport thread.
+
+        @param profile_name: the X2go session profile name
+        @type session_uuid: C{str}
+        """
+        for s in self.session_registry.registered_sessions_of_name(profile_name):
+            s.disconnect()
+    __disconnect_profile = disconnect_profile
+
+    def update_cache_by_profile(self, profile_name, seconds=None):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        if self.listsessions_cache is not None:
+            try:
+                self.listsessions_cache.update(profile_name, seconds=seconds)
+            except x2go_exceptions.X2goControlSessionException:
+                self.HOOK_on_control_session_death(profile_name)
+                self.disconnect_profile(profile_name, seconds=seconds)
+    __update_cache_by_profile = update_cache_by_profile
+
+    def update_cache_by_session_uuid(self, session_uuid, seconds=None):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        profile_name = self.get_session_profile_name(session_uuid)
+        self.__update_cache_by_profile(profile_name, seconds=seconds)
+    __update_cache_by_session_uuid = update_cache_by_session_uuid
+
+    def update_cache_all_profiles(self, seconds=None):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        if self.listsessions_cache is not None:
+            for profile_id in self.connected_profiles:
+                profile_name = self.to_profile_name(profile_id)
+                self.__update_cache_by_profile(profile_name, seconds=seconds)
 
+            self.listsessions_cache.check_cache(seconds=seconds)
+    __update_cache_all_profiles = update_cache_all_profiles
diff --git a/x2go/defaults.py b/x2go/defaults.py
index 1a04b5f..5f61493 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -46,7 +46,7 @@ if X2GOCLIENT_OS == "Windows":
     SUPPORTED_SOUND = False
     SUPPORTED_PRINTING = True
     SUPPORTED_FOLDERSHARING = True
-    DISPLAY='localhost:0.0'
+    DISPLAY='127.0.0.1:0.0'
     os.environ['DISPLAY'] = DISPLAY
 
 elif X2GOCLIENT_OS == "Linux":
@@ -182,7 +182,6 @@ X2GO_SESSIONPROFILE_DEFAULTS = {
     'host': None, 'user': None, 'key': None, 'sshport': 22, 'add_to_known_hosts': True,
     'rootless': True, 'applications': 'WWWBROWSER, MAILCLIENT, OFFICE, TERMINAL', 'command':'TERMINAL', 'session_type': 'application',
     'rdpoptions':None, 'rdpserver':None, 
-    'default':False,
     'print': True,
     'xdmcpserver': 'localhost',
     }
diff --git a/x2go/guardian.py b/x2go/guardian.py
index 176c274..0195c73 100644
--- a/x2go/guardian.py
+++ b/x2go/guardian.py
@@ -49,14 +49,7 @@ class X2goSessionGuardian(threading.Thread):
 
     """
 
-    active_threads = []
-    """\
-    List of active threads that this L{X2goSessionGuardian} instance will monitor. Whenever
-    an L{X2goSession} starts a new sub-thread, it will be appended to this list.
-
-    """
-
-    def __init__(self, terminal_session, logger=None, loglevel=log.loglevel_DEFAULT):
+    def __init__(self, client, enable_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         @param terminal_session: the L{X2goTerminalSession} that is controlled by this L{X2goSessionGuardian}
         @type terminal_session: C{instance}
@@ -67,17 +60,17 @@ class X2goSessionGuardian(threading.Thread):
         @type loglevel: C{int}
 
         """
-        self.active_threads = []
-
         if logger is None:
             self.logger = log.X2goLogger(loglevel=loglevel)
         else:
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
-        self.terminal_session = terminal_session
+        self.client = client
+        self.enable_cache = enable_cache
         threading.Thread.__init__(self, target=self.guardian)
         self.daemon = True
+        self.start()
 
     def guardian(self):
         """\
@@ -91,11 +84,15 @@ class X2goSessionGuardian(threading.Thread):
         while not _sigterm_received and self._keepalive:
             gevent.sleep(1)
             seconds += 1
+            if self.enable_cache:
+                self.client.update_cache_all_profiles(seconds)
 
         self.logger('X2go session guardian thread waking up after %s seconds' % seconds, loglevel=log.loglevel_DEBUG)
-        self.logger('calling terminal session cleanup for terminal session: %s' % self.terminal_session.session_info.name, loglevel=log.loglevel_DEBUG)
 
-        x2go_cleanup(terminal_session=self.terminal_session, threads=self.active_threads)
+        for session_uuid in self.client.session_registry.keys():
+            session_summary = self.client.get_session_summary(session_uuid)
+            self.logger('calling session cleanup on profile %s for terminal session: %s' % (session_summary['profile_name'], session_summary['session_name']), loglevel=log.loglevel_DEBUG)
+            x2go_cleanup(threads=session_summary['active_threads'])
 
     def stop_thread(self):
         """\
diff --git a/x2go/registry.py b/x2go/registry.py
index ec6587c..95f25e3 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -46,7 +46,7 @@ class X2goSessionRegistry(object):
     STILL UNDOCUMENTED
 
     """
-    def __init__(self, logger=None, loglevel=log.loglevel_DEFAULT):
+    def __init__(self, use_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
         """\
         STILL UNDOCUMENTED
 
@@ -88,6 +88,34 @@ class X2goSessionRegistry(object):
         """
         return self(session_uuid).profile.profile_name
 
+    def session_summary(self, session_uuid):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        _session_summary = {}
+        _session_summary['uuid'] = session_uuid
+        _session_summary['profile_id'] = self.get_profile_id(session_uuid)
+        _session_summary['profile_name'] = self.get_profile_name(session_uuid)
+        _session_summary['session_name'] = self(session_uuid).get_session_name()
+        _session_summary['control_session'] = self(session_uuid).get_control_session()
+        _session_summary['control_params'] = self(session_uuid).control_params
+        _session_summary['terminal_session'] = self(session_uuid).get_terminal_session()
+        _session_summary['terminal_params'] = self(session_uuid).terminal_params
+        _session_summary['active_threads'] = self(session_uuid).get_terminal_session().active_threads
+        _session_summary['connected'] = self(session_uuid).connected
+        _session_summary['running'] = self(session_uuid).running
+        _session_summary['suspended'] = self(session_uuid).suspended
+        _session_summary['terminated'] = self(session_uuid).terminated
+        _session_summary['backends'] = {
+            'control': self(session_uuid)._control_backend,
+            'terminal': self(session_uuid)._terminal_backend,
+            'info': self(session_uuid)._info_backend,
+            'list': self(session_uuid)._list_backend,
+            'proxy': self(session_uuid)._proxy_backend,
+        }
+        return _session_summary
+
     def register(self, server, profile_id, profile_name, 
                  control_backend=X2goControlSession,
                  terminal_backend=X2goTerminalSession,
@@ -101,7 +129,7 @@ class X2goSessionRegistry(object):
             control_session = self.control_sessions[profile_id]
 
         s = session.X2goSession(server=server, control_session=control_session,
-                                profile_id=profile_id, profile_name=profile_name, 
+                                profile_id=profile_id, profile_name=profile_name,
                                 control_backend=control_backend,
                                 terminal_backend=terminal_backend,
                                 info_backend=info_backend,
@@ -131,6 +159,14 @@ class X2goSessionRegistry(object):
         return self._sessionsWithState('connected')
 
     @property
+    def connected_sessions(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self._sessionsWithState('connected')
+
+    @property
     def running_sessions(self):
         """\
         STILL UNDOCUMENTED
@@ -206,3 +242,29 @@ class X2goSessionRegistry(object):
 
             """
         return self.running_sessions and [ s for s in self.running_sessions if s.profile_name == profile_name ]
+
+    def control_session_of_name(self, profile_name):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        if self.registered_sessions_of_name(profile_name):
+            session = self.registered_sessions_of_name(profile_name)[0]
+            return session.control_session
+        return None
+
+    @property
+    def connected_control_sessions(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return [ c for c in self.control_sessions.values() if c.is_connected() ]
+
+    @property
+    def connected_profiles(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return [ p for p in self.control_sessions.keys() if self.control_sessions[p].is_connected() ]
diff --git a/x2go/session.py b/x2go/session.py
index 2c6129f..42018fc 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -54,15 +54,7 @@ _X2GO_SESSION_PARAMS = ('geometry', 'depth', 'link', 'pack',
 
 class X2goSession(object):
 
-    # user hooks for detecting/notifying what happened with this session 
-    def __hook_session_has_died(self):
-        self.logger('the control session of session %s has unexpectedly died' % self.get_session_name())
-    def __hook_session_suspended(self):
-        self.logger('session %s has been suspended from within the application' % self.get_session_name())
-    def __hook_session_terminated(self):
-        self.logger('session %s has been terminated from within the application' % self.get_session_name())
-
-    def __init__(self, server, control_session=None,
+    def __init__(self, server=None, control_session=None,
                  profile_id=None, profile_name=None,
                  printing=None, share_local_folders=[],
                  control_backend=X2goControlSession,
@@ -123,29 +115,36 @@ class X2goSession(object):
                                                    info_backend=info_backend,
                                                    list_backend=list_backend,
                                                    proxy_backend=proxy_backend,
-                                                   controlled_session=self,
                                                    logger=logger)
         else:
             self.control_session = control_session
-            self.control_session.controlled_sessions[self.get_uuid()] = self
 
         self.terminal_session = None
-        self.guardian_thread = None
         self.logger('starting X2goSession', loglevel=log.loglevel_DEBUG)
         if known_hosts:
             self.control_session.load_host_keys(known_hosts)
 
     def __str__(self):
         return self.__get_uuid()
+
     def __repr__(self):
         result = 'X2goSession('
         for p in dir(self):
             if '__' in p or not p in self.__dict__ or type(p) is types.InstanceType: continue
             result += p + '=' + str(self.__dict__[p]) + ', '
         return result + ')'
+
     def __call__(self):
         return self.__get_uuid()
 
+    # user hooks for detecting/notifying what happened with this session 
+    def HOOK_session_has_died(self):
+        self.logger('the control session of session %s has unexpectedly died' % self.get_session_name())
+    def HOOK_session_suspended(self):
+        self.logger('session %s has been suspended from within the application' % self.get_session_name())
+    def HOOK_session_terminated(self):
+        self.logger('session %s has been terminated from within the application' % self.get_session_name())
+
     def get_uuid(self):
         """\
         STILL UNDOCUMENTED
@@ -320,10 +319,10 @@ class X2goSession(object):
             self._X2goSession__disconnect()
     __clean_sessions = clean_sessions
 
-    def list_sessions(self, no_cache=False, refresh_cache=False):
-        if (no_cache or refresh_cache) and not self.is_alive():
+    def list_sessions(self):
+        if not self.is_alive():
             self._X2goSession__disconnect()
-        return self.control_session.list_sessions(no_cache=no_cache, refresh_cache=refresh_cache)
+        return self.control_session.list_sessions()
     __list_sessions = list_sessions
 
     def resume(self, session_name=None):
@@ -337,8 +336,8 @@ class X2goSession(object):
         """
         if self.is_alive():
             _control = self.control_session
-            _terminal = _control.resume(session_name=session_name, logger=self.logger, **self.terminal_params)
-            self.guardian_thread = _terminal.guardian_thread
+            _terminal = _control.resume(session_name=session_name, 
+                                        logger=self.logger, **self.terminal_params)
             self.terminal_session = _terminal
             if _terminal is not None:
 
diff --git a/x2go/utils.py b/x2go/utils.py
index bee7149..58c4c7a 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -203,7 +203,6 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
             'rdpoptions',
             'rdpserver',
             'xdmcpserver',
-            'default',
         ]
         for i in _ignored_options:
             del _params[i]
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index 950a0c7..3b4e396 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -39,8 +39,9 @@ SSHException = paramiko.SSHException
 
 class _X2goException(exceptions.BaseException): pass
 class X2goClientException(_X2goException): pass
-class X2goSessionException(_X2goException): pass
-class X2goSessionException(_X2goException): pass
+class X2goControlSessionException(_X2goException): pass
+class X2goTerminalSessionException(_X2goException): pass
+class X2goSessionCacheException(_X2goException): pass
 class X2goUserException(_X2goException): pass
 class X2goProfileException(_X2goException): pass
 class X2goSettingsException(_X2goException): pass


hooks/post-receive
-- 
python-x2go.git (Python X2Go Client API)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2Go Client API).




More information about the x2go-commits mailing list