1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """\
21 X2GoListSessionCache class - caching X2Go session information.
22
23 """
24 __NAME__ = 'x2gocache-pylib'
25
26
27 import copy
28 import gevent
29
30
31 import log
32 import x2go_exceptions
33
35 """\
36 For non-blocking operations in client applications using Python X2Go, it is
37 recommended to enable the L{X2GoListSessionsCache}. This can be done by calling
38 the constructor of the L{X2GoClient} class.
39
40 The session list and desktop cache gets updated in regular intervals by a threaded
41 L{X2GoSessionGuardian} instance. For the session list and desktop list update, the
42 X2Go server commands C{x2golistsessions} and C{x2godesktopsessions} are called and
43 the command's stdout is cached in the session list cache.
44
45 Whenever your client application needs access to either the server's session list
46 or the server's desktop list the session cache is queried instead. This assures that
47 the server's session/desktop list is available without delay, even on slow internet
48 connections.
49
50 """
51 x2go_listsessions_cache = {}
52
54 """\
55 @param client_instance: the L{X2GoClient} instance that uses this L{X2GoListSessionsCache}
56 @type client_instance: C{obj}
57 @param logger: you can pass an L{X2GoLogger} object to the L{X2GoListSessionsCache} constructor
58 @type logger: C{obj}
59 @param loglevel: if no L{X2GoLogger} object has been supplied a new one will be
60 constructed with the given loglevel
61 @type loglevel: C{int}
62
63 """
64 self.x2go_listsessions_cache = {}
65 self.last_listsessions_cache = {}
66 self.protected = False
67
68 if logger is None:
69 self.logger = log.X2GoLogger(loglevel=loglevel)
70 else:
71 self.logger = copy.deepcopy(logger)
72 self.logger.tag = __NAME__
73
74 self.client_instance = client_instance
75
76 - def delete(self, profile_name):
77 """\
78 Remove session list from cache for a given profile.
79
80 @param profile_name: name of profile to operate on
81 @type profile_name: C{str}
82
83 """
84 while self.protected:
85 gevent.sleep(.1)
86 try: del self.x2go_listsessions_cache[profile_name]
87 except KeyError: pass
88
90 """\
91 Check if session list cache elements are still valid (i.e. if all corresponding
92 session profiles are still connected). If not so, remove invalid cache entries from
93 the session list cache.
94
95 """
96 for profile_name in self.x2go_listsessions_cache.keys():
97 if profile_name not in self.client_instance.client_connected_profiles(return_profile_names=True):
98 del self.x2go_listsessions_cache[profile_name]
99
100 - def update_all(self, update_sessions=True, update_desktops=False):
101 """\
102 Update L{X2GoListSessionsCache} for all connected session profiles.
103
104 @param update_sessions: cache recent session lists from all connected servers
105 @type update_sessions: C{bool}
106 @param update_desktops: cache recent desktop lists from all connected servers
107 @type update_desktops: C{bool}
108
109 """
110 for profile_name in self.client_instance.client_connected_profiles(return_profile_names=True):
111 self.update(profile_name, update_sessions=update_sessions, update_desktops=update_desktops)
112
113 self.check_cache()
114
115 - def update(self, profile_name, update_sessions=True, update_desktops=False, update_mounts=False):
116 """\
117 Update L{X2GoListSessionsCache} (i.e. session/desktops) for session profile C{profile_name}.
118
119 @param profile_name: name of profile to update
120 @type profile_name: C{str}
121 @param update_sessions: cache recent session list from server
122 @type update_sessions: C{bool}
123 @param update_desktops: cache recent desktop list from server
124 @type update_desktops: C{bool}
125 @param update_mounts: cache list of client-side mounts on server
126 @type update_mounts: C{bool}
127
128 """
129 self.protected = True
130 self.last_listsessions_cache = copy.deepcopy(self.x2go_listsessions_cache)
131 control_session = self.client_instance.client_control_session_of_profile_name(profile_name)
132 if not self.x2go_listsessions_cache.has_key(profile_name):
133 self.x2go_listsessions_cache[profile_name] = {'sessions': None, 'desktops': None, 'mounts': {}, }
134 if update_sessions:
135 self._update_sessions(profile_name, control_session)
136 if update_desktops:
137 self._update_desktops(profile_name, control_session)
138 if update_mounts:
139 self._update_mounts(profile_name, control_session)
140 self.protected = False
141
168
192
212
214 """\
215 Retrieve a session list from the current cache content of L{X2GoListSessionsCache}
216 for a given L{X2GoSession} instance (specified by its unique session UUID).
217
218 @param session_uuid: unique identifier of session to query cache for
219 @type session_uuid: C{str}
220
221 @return: a data object containing available session information
222 @rtype: C{X2GoServerSessionList*} instance (or C{None})
223
224 """
225 profile_name = self.client_instance.get_session_profile_name(session_uuid)
226 if self.is_cached(session_uuid=session_uuid):
227 return self.x2go_listsessions_cache[profile_name]['sessions']
228 else:
229 return None
230
232 """\
233 Retrieve a list of available desktop sessions from the current cache content of
234 L{X2GoListSessionsCache} for a given L{X2GoSession} instance (specified by its
235 unique session UUID).
236
237 @param session_uuid: unique identifier of session to query cache for
238 @type session_uuid: C{str}
239
240 @return: a list of strings representing X2Go desktop sessions available for sharing
241 @rtype: C{list} (or C{None})
242
243 """
244 profile_name = self.client_instance.get_session_profile_name(session_uuid)
245 if self.is_cached(session_uuid=session_uuid):
246 return self.x2go_listsessions_cache[profile_name]['desktops']
247 else:
248 return None
249
251 """\
252 Retrieve a list of mounted client shares from the current cache content of
253 L{X2GoListSessionsCache} for a given L{X2GoSession} instance (specified by its
254 unique session UUID).
255
256 @param session_uuid: unique identifier of session to query cache for
257 @type session_uuid: C{str}
258
259 @return: a list of strings representing mounted client shares
260 @rtype: C{list} (or C{None})
261
262 """
263 profile_name = self.client_instance.get_session_profile_name(session_uuid)
264 if self.is_cached(session_uuid=session_uuid):
265 return self.x2go_listsessions_cache[profile_name]['mounts']
266 else:
267 return None
268
269 - def is_cached(self, profile_name=None, session_uuid=None, cache_type=None):
270 """\
271 Check if session information is cached.
272
273 @param profile_name: name of profile to update
274 @type profile_name: C{str}
275 @param session_uuid: unique identifier of session to query cache for
276 @type session_uuid: C{str}
277
278 @return: C{True} if session information is cached
279 @rtype: C{bool}
280
281 """
282 if profile_name is None and session_uuid and self.client_instance:
283 try:
284 profile_name = self.client_instance.get_session_profile_name(session_uuid)
285 except x2go_exceptions.X2GoSessionRegistryException:
286 raise x2go_exceptions.X2GoSessionCacheException("requested session UUID is not valid anymore")
287 _is_profile_cached = self.x2go_listsessions_cache.has_key(profile_name)
288 _is_cache_type_cached = _is_profile_cached and self.x2go_listsessions_cache[profile_name].has_key(cache_type)
289 if cache_type is None:
290 return _is_profile_cached
291 else:
292 return _is_cache_type_cached
293