1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """\
21 L{X2GoMIMEboxQueue} sets up a thread that listens for incoming files that
22 shall be opened locally on the client.
23
24 For each file that gets dropped in the MIME box an individual
25 thread is started (L{X2GoMIMEboxJob}) that handles the processing
26 of the incoming file.
27
28 """
29 __NAME__ = 'x2gomimeboxqueue-pylib'
30
31
32 import os
33 import copy
34 import types
35 import threading
36 import gevent
37
38
39 import defaults
40 import utils
41 import log
42 import mimeboxactions
46 """\
47 If the X2Go MIME box is supported in a particaluar L{X2GoSession} instance
48 this class provides a sub-thread for handling incoming files in the MIME box
49 directory. The actual handling of a dropped file is handled by the classes
50 L{X2GoMIMEboxActionOPEN}, L{X2GoMIMEboxActionOPENWITH} and L{X2GoMIMEboxActionSAVEAS}.
51
52 """
53 mimebox_action = None
54
55 mimebox = None
56 active_jobs = {}
57 mimebox_history = []
58
59 - def __init__(self, profile_name='UNKNOWN', session_name='UNKNOWN',
60 mimebox_dir=None, mimebox_action=None, mimebox_extensions=[],
61 client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
62 """\
63 @param profile_name: name of the session profile this print queue belongs to
64 @type profile_name: C{str}
65 @param mimebox_dir: local directory for incoming MIME box files
66 @type mimebox_dir: C{str}
67 @param mimebox_action: name or instance of either of the possible X2Go print action classes
68 @type mimebox_action: C{str} or instance
69 @param client_instance: the underlying L{X2GoClient} instance
70 @type client_instance: C{obj}
71 @param logger: you can pass an L{X2GoLogger} object to the
72 L{X2GoPrintQueue} constructor
73 @type logger: C{obj}
74 @param loglevel: if no L{X2GoLogger} object has been supplied a new one will be
75 constructed with the given loglevel
76 @type loglevel: C{int}
77
78 """
79 if logger is None:
80 self.logger = log.X2GoLogger(loglevel=loglevel)
81 else:
82 self.logger = copy.deepcopy(logger)
83 self.logger.tag = __NAME__
84
85 self.profile_name = profile_name
86 self.session_name = session_name
87 self.mimebox_dir = mimebox_dir
88 if self.mimebox_dir: self.mimebox_dir = os.path.normpath(self.mimebox_dir)
89 self.mimebox_extensions = mimebox_extensions
90 self.client_instance = client_instance
91 self.client_rootdir = client_instance.get_client_rootdir()
92
93
94 self._accept_jobs = False
95
96 if mimebox_action is None:
97 mimebox_action = mimeboxactions.X2GoMIMEboxActionOPEN(client_instance=self.client_instance, logger=self.logger)
98 elif type(mimebox_action) in (types.StringType, types.UnicodeType):
99 mimebox_action = self.set_mimebox_action(mimebox_action, client_instance=self.client_instance, logger=self.logger)
100 else:
101
102 self.mimebox_action = mimebox_action
103
104 threading.Thread.__init__(self)
105 self.daemon = True
106 self._accept_jobs = True
107
108
110 """\
111 Class destructor.
112
113 """
114 self.stop_thread()
115
117 """\
118 Prevent acceptance of new incoming files. The processing of MIME box jobs that
119 are currently still active will be completed, though.
120
121 """
122 if self._accept_jobs == True:
123 self._accept_jobs = False
124 self.logger('paused thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
125
127 """\
128 Resume operation of the X2Go MIME box queue and continue accepting new incoming
129 files.
130
131 """
132 if self._accept_jobs == False:
133 self._accept_jobs = True
134 self.logger('resumed thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
135
137 """\
138 Stops this L{X2GoMIMEboxQueue} thread completely.
139
140 """
141 self.pause()
142 self._keepalive = False
143 self.logger('stopping thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
144
145 @property
147 if os.path.exists(self.mimebox_dir):
148 l = os.listdir(self.mimebox_dir)
149 mimebox_jobs = []
150 for _ext in self.mimebox_extensions:
151 mimebox_jobs.extend([ dj for dj in l if dj.upper().endswith(_ext.upper()) ])
152 else:
153 mimebox_jobs = l
154 return [ dj for dj in mimebox_jobs if dj not in self.active_jobs.keys() ]
155 else:
156 return []
157
175
177 """\
178 This method gets called once the L{X2GoMIMEboxQueue} thread is started by the C{X2GoMIMEboxQueue.start()} method.
179
180 """
181 self.logger('starting MIME box queue thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
182
183 self._keepalive = True
184 while self._keepalive:
185
186 while self._accept_jobs:
187
188 if self._incoming_mimebox_jobs:
189
190 for _job in self._incoming_mimebox_jobs:
191 self.logger('processing incoming X2Go MIME box job: %s' % _job, loglevel=log.loglevel_NOTICE)
192 _new_mimeboxjob_thread = X2GoMIMEboxJob(target=x2go_mimeboxjob_handler,
193 kwargs={
194 'mimebox_file': _job,
195 'mimebox_extensions': self.mimebox_extensions,
196 'mimebox_action': self.mimebox_action,
197 'parent_thread': self,
198 'logger': self.logger,
199 }
200 )
201 self.active_jobs['%s' % _job] = _new_mimeboxjob_thread
202 _new_mimeboxjob_thread.start()
203
204 gevent.sleep(3)
205
206 gevent.sleep(1)
207
208
209 -def x2go_mimeboxjob_handler(mimebox_file=None,
210 mimebox_extensions=[],
211 mimebox_action=None,
212 parent_thread=None, logger=None, ):
213 """\
214 This function is called as a handler function for each incoming X2Go MIME box file
215 represented by the class L{X2GoMIMEboxJob}.
216
217 @param mimebox_file: MIME box file name as placed in to the X2Go MIME box spool directory
218 @type mimebox_file: C{str}
219 @param mimebox_action: an instance of either of the possible C{X2GoMIMEboxActionXXX} classes
220 @type mimebox_action: C{X2GoMIMEboxActionXXX} nstance
221 @param parent_thread: the L{X2GoMIMEboxQueue} thread that actually created this handler's L{X2GoMIMEboxJob} instance
222 @type parent_thread: C{obj}
223 @param logger: the L{X2GoMIMEboxQueue}'s logging instance
224 @type logger: C{obj}
225
226 """
227 mimebox_action.profile_name = parent_thread.profile_name
228 mimebox_action.session_name = parent_thread.session_name
229
230 logger('action for printing is: %s' % mimebox_action, loglevel=log.loglevel_DEBUG)
231
232 _dotfile = mimebox_file.startswith('.')
233 _blacklisted = mimebox_file.upper().split('.')[-1] in defaults.X2GO_MIMEBOX_EXTENSIONS_BLACKLIST
234 _really_process = bool(not _blacklisted and ((not mimebox_extensions) or [ ext for ext in mimebox_extensions if mimebox_file.upper().endswith('%s' % ext.upper()) ]))
235 if _really_process and not _blacklisted and not _dotfile:
236 mimebox_action.do_process(mimebox_file=mimebox_file,
237 mimebox_dir=parent_thread.mimebox_dir,
238 )
239 elif not _blacklisted and not _dotfile:
240 logger('file extension of MIME box file %s is prohibited by session profile configuration' % mimebox_file, loglevel=log.loglevel_NOTICE)
241 elif _dotfile:
242 logger('placing files starting with a dot (.<file>) into the X2Go MIME box is prohibited, ignoring the file ,,%s\'\'' % mimebox_file, loglevel=log.loglevel_WARN)
243 else:
244 logger('file extension of MIME box file %s has been found in Python X2Go\' hardcoded MIME box extenstions blacklist' % mimebox_file, loglevel=log.loglevel_WARN)
245
246 logger('removing MIME box file %s' % mimebox_file, loglevel=log.loglevel_DEBUG)
247
248 utils.patiently_remove_file(parent_thread.mimebox_dir, mimebox_file)
249 logger('removed print job file %s' % mimebox_file, loglevel=log.loglevel_DEBUG)
250
251 del parent_thread.active_jobs['%s' % mimebox_file]
252 parent_thread.mimebox_history.append(mimebox_file)
253
254
255 if len(parent_thread.mimebox_history) > 100:
256 parent_thread.mimebox_history = parent_thread.mimebox_history[-100:]
257
260 """\
261 For each X2Go MIME box job we create a sub-thread that let's
262 the MIME box job be processed in the background.
263
264 As a handler for this class the function L{x2go_mimeboxjob_handler()}
265 is used.
266
267 """
269 """\
270 Construct the X2Go MIME box job thread...
271
272 All parameters (**kwargs) are passed through to the constructor
273 of C{threading.Thread()}.
274
275 """
276 threading.Thread.__init__(self, **kwargs)
277 self.daemon = True
278