# Python X2Go (Client) API Documentation (v0.6.1.4)

## x2go.guardian

# Source code for x2go.guardian

    # -*- coding: utf-8 -*-

    # Copyright (C) 2010-2023 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
    #
    # Python X2Go is free software; you can redistribute it and/or modify
    # it under the terms of the GNU Affero General Public License as published by
    # the Free Software Foundation; either version 3 of the License, or
    # (at your option) any later version.
    #
    # Python X2Go is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU Affero General Public License for more details.
    #
    # You should have received a copy of the GNU Affero General Public License
    # along with this program; if not, write to the
    # Free Software Foundation, Inc.,
    # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

    """\
    X2GoSessionGuardian class - a guardian thread that controls X2Go session threads
    and their sub-threads (like reverse forwarding tunnels, Paramiko transport threads,
    etc.).

    """
    __NAME__ = 'x2goguardian-pylib'

    __package__ = 'x2go'
    __name__    = 'x2go.guardian'

    # modules
    import gevent
    import threading
    import copy

    # Python X2Go modules
    from .cleanup import x2go_cleanup
    from . import log

    class X2GoSessionGuardian(threading.Thread):
        """\
        :class:`x2go.guardian.X2GoSessionGuardian` thread controls X2Go session threads and their sub-threads (like
        reverse forwarding tunnels, Paramiko transport threads, etc.). Its main function is
        to tidy up once a session gets interrupted (SIGTERM, SIGINT).

        There is one :class:`x2go.guardian.X2GoSessionGuardian` for each :class:`x2go.client.X2GoClient` instance (thus: for normal
        setups there should be _one_ :class:`x2go.client.X2GoClient` and _one_ :class:`x2go.guardian.X2GoSessionGuardian` in use).

        """
        def __init__(self, client_instance,
                     auto_update_listsessions_cache=False,
                     auto_update_listdesktops_cache=False,
                     auto_update_listmounts_cache=False,
                     auto_update_sessionregistry=False,
                     auto_register_sessions=False,
                     no_auto_reg_pubapp_sessions=False,
                     refresh_interval=5,
                     logger=None, loglevel=log.loglevel_DEFAULT):
            """\
            :param auto_update_listsessions_cache: let :class:`x2go.guardian.X2GoSessionGuardian` refresh the session list cache for all :class:`x2go.session.X2GoSession` objects
            :type auto_update_listsessions_cache: ``bool``
            :param auto_update_listdesktops_cache: let :class:`x2go.guardian.X2GoSessionGuardian` refresh desktop lists in the session list cache for all :class:`x2go.session.X2GoSession` objects
            :type auto_update_listdesktops_cache: ``bool``
            :param auto_update_listmounts_cache: let :class:`x2go.guardian.X2GoSessionGuardian` refresh mount lists in the session list cache for all :class:`x2go.session.X2GoSession` objects
            :type auto_update_listmounts_cache: ``bool``
            :param auto_update_sessionregistry: if set to ``True`` the session status will be updated in regular intervals
            :type auto_update_sessionregistry: ``bool``
            :param auto_register_sessions: register new sessions automatically once they appear in the X2Go session (e.g.
                instantiated by another client that is connected to the same X2Go server under same user ID)
            :type auto_register_sessions: ``bool``
            :param no_auto_reg_pubapp_sessions: do not auto-register published applications sessions
            :type no_auto_reg_pubapp_sessions: ``bool``
            :param refresh_interval: refresh cache and session registry every <refresh_interval> seconds
            :type refresh_interval: ``int``
            :param logger: you can pass an :class:`x2go.log.X2GoLogger` object to the :class:`x2go.guardian.X2GoSessionGuardian` constructor
            :type logger: ``obj``
            :param loglevel: if no :class:`x2go.log.X2GoLogger` object has been supplied a new one will be
                constructed with the given loglevel
            :type loglevel: ``int``

            """
            if logger is None:
                self.logger = log.X2GoLogger(loglevel=loglevel)
            else:
                self.logger = copy.deepcopy(logger)
            self.logger.tag = __NAME__

            self.client_instance = client_instance
            self.auto_update_listsessions_cache = auto_update_listsessions_cache
            self.auto_update_listdesktops_cache = auto_update_listdesktops_cache
            self.auto_update_listmounts_cache = auto_update_listmounts_cache
            self.auto_update_sessionregistry = auto_update_sessionregistry
            self.auto_register_sessions = auto_register_sessions
            self.no_auto_reg_pubapp_sessions = no_auto_reg_pubapp_sessions
            self.refresh_interval = refresh_interval

            threading.Thread.__init__(self, target=self.guardian)
            self.daemon = True
            self.start()

        def guardian(self):
            """\
            The handler of this :class:`x2go.guardian.X2GoSessionGuardian` thread.

            """
            seconds = 0
            self._keepalive = True
            while self._keepalive:
                gevent.sleep(1)
                seconds += 1

                if seconds % self.refresh_interval == 0:

                    self.logger('Entering X2Go Guardian client management loop...', loglevel=log.loglevel_DEBUG)

                    if self.auto_update_listsessions_cache:
                        self.client_instance.update_cache_all_profiles(update_sessions=self.auto_update_listsessions_cache,
                                                                       update_desktops=self.auto_update_listdesktops_cache,
                                                                       update_mounts=self.auto_update_listmounts_cache,
                                                                      )

                    if self.auto_update_sessionregistry and not self.auto_register_sessions:
                        self.client_instance.update_sessionregistry_status_all_profiles()

                    # session auto-registration will automatically trigger an update of the session registry status
                    if self.auto_register_sessions:
                        self.client_instance.register_available_server_sessions_all_profiles(skip_pubapp_sessions=self.no_auto_reg_pubapp_sessions)

            self.logger('X2Go session guardian thread waking up after %s seconds' % seconds, loglevel=log.loglevel_DEBUG)

            for session_uuid in list(self.client_instance.session_registry.keys()):
                session_summary = self.client_instance.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):
            """\
            Stop this :class:`x2go.guardian.X2GoSessionGuardian` thread.

            """
            self._keepalive = False