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