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

X2Go dev team git-admin at x2go.org
Sat Sep 14 15:55:30 CEST 2013


The branch, twofactorauth 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