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
44
45 if defaults.X2GOCLIENT_OS != 'Windows':
46 from x2go_exceptions import WindowsError
50 """\
51 If the X2go MIME box is supported in a particaluar L{X2goSession} instance
52 this class provides a sub-thread for handling incoming files in the MIME box
53 directory. The actual handling of a dropped file is handled by the classes
54 L{X2goMIMEboxActionOPEN}, L{X2goMIMEboxActionOPENWITH} and L{X2goMIMEboxActionSAVEAS}.
55
56 """
57 mimebox_action = None
58
59 mimebox = None
60 active_jobs = {}
61 mimebox_history = []
62
63 - def __init__(self, profile_name='UNKNOWN', session_name='UNKNOWN',
64 mimebox_dir=None, mimebox_action=None, mimebox_extensions=[],
65 client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
66 """\
67 @param profile_name: name of the session profile this print queue belongs to
68 @type profile_name: C{str}
69 @param mimebox_dir: local directory for incoming MIME box files
70 @type mimebox_dir: C{str}
71 @param mimebox_action: name or instance of either of the possible X2go print action classes
72 @type mimebox_action: C{str} or instance
73 @param client_instance: the underlying L{X2goClient} instance
74 @type client_instance: C{instance}
75 @param logger: you can pass an L{X2goLogger} object to the
76 L{X2goPrintQueue} constructor
77 @type logger: C{instance}
78 @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
79 constructed with the given loglevel
80 @type loglevel: C{int}
81
82 """
83 if logger is None:
84 self.logger = log.X2goLogger(loglevel=loglevel)
85 else:
86 self.logger = copy.deepcopy(logger)
87 self.logger.tag = __NAME__
88
89 self.profile_name = profile_name
90 self.session_name = session_name
91 self.mimebox_dir = mimebox_dir
92 self.mimebox_extensions = mimebox_extensions
93 self.client_instance = client_instance
94 self.client_rootdir = client_instance.get_client_rootdir()
95
96
97 self._accept_jobs = False
98
99 if mimebox_action is None:
100 mimebox_action = mimebox_actions.X2goMIMEboxActionOPEN(client_instance=self.client_instance, logger=self.logger)
101 elif type(mimebox_action) in (types.StringType, types.UnicodeType):
102 mimebox_action = self.set_mimebox_action(mimebox_action, client_instance=self.client_instance, logger=self.logger)
103 else:
104
105 self.mimebox_action = mimebox_action
106
107 threading.Thread.__init__(self)
108 self.daemon = True
109 self._accept_jobs = True
110
111
113 """\
114 Class destructor.
115
116 """
117 self.stop_thread()
118
120 """\
121 Prevent acceptance of new incoming files. The processing of MIME box jobs that
122 are currently still active will be completed, though.
123
124 """
125 if self._accept_jobs == True:
126 self._accept_jobs = False
127 self.logger('paused thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
128
130 """\
131 Resume operation of the X2go MIME box queue and continue accepting new incoming
132 files.
133
134 """
135 if self._accept_jobs == False:
136 self._accept_jobs = True
137 self.logger('resumed thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
138
140 """\
141 Stops this L{X2goMIMEboxQueue} thread completely.
142
143 """
144 self.pause()
145 self._keepalive = False
146 self.logger('stopping thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
147
148 @property
150 if os.path.exists(self.mimebox_dir):
151 l = os.listdir(self.mimebox_dir)
152 mimebox_jobs = []
153 for _ext in self.mimebox_extensions:
154 mimebox_jobs.extend([ dj for dj in l if dj.upper().endswith(_ext.upper()) ])
155 else:
156 mimebox_jobs = l
157 return [ dj for dj in mimebox_jobs if dj not in self.active_jobs.keys() ]
158 else:
159 return []
160
173
175 """\
176 This method gets called once the L{X2goMIMEboxQueue} thread is started by the C{X2goMIMEboxQueue.start()} method.
177
178 """
179 self.logger('starting MIME box queue thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
180
181 self._keepalive = True
182 while self._keepalive:
183
184 while self._accept_jobs:
185
186 if self._incoming_mimebox_jobs:
187
188 for _job in self._incoming_mimebox_jobs:
189 self.logger('processing incoming X2go MIME box job: %s' % _job, loglevel=log.loglevel_NOTICE)
190 _new_mimeboxjob_thread = X2goMIMEboxJob(target=x2go_mimeboxjob_handler,
191 kwargs={
192 'mimebox_file': _job,
193 'mimebox_extensions': self.mimebox_extensions,
194 'mimebox_action': self.mimebox_action,
195 'parent_thread': self,
196 'logger': self.logger,
197 }
198 )
199 self.active_jobs['%s' % _job] = _new_mimeboxjob_thread
200 _new_mimeboxjob_thread.start()
201
202 gevent.sleep(3)
203
204 gevent.sleep(1)
205
206
207 -def x2go_mimeboxjob_handler(mimebox_file=None,
208 mimebox_extensions=[],
209 mimebox_action=None,
210 parent_thread=None, logger=None, ):
211 """\
212 This function is called as a handler function for each incoming X2go MIME box file
213 represented by the class L{X2goMIMEboxJob}.
214
215 @param mimebox_file: MIME box file name as placed in to the X2go MIME box spool directory
216 @type mimebox_file: C{str}
217 @param mimebox_action: an instance of either of the possible C{X2goMIMEboxActionXXX} classes
218 @type mimebox_action: C{X2goMIMEboxActionXXX} nstance
219 @param parent_thread: the L{X2goMIMEboxQueue} thread that actually created this handler's L{X2goMIMEboxJob} instance
220 @type parent_thread: C{instance}
221 @param logger: the L{X2goMIMEboxQueue}'s logging instance
222 @type logger: C{instance}
223
224 """
225 mimebox_action.profile_name = parent_thread.profile_name
226 mimebox_action.session_name = parent_thread.session_name
227
228 logger('action for printing is: %s' % mimebox_action, loglevel=log.loglevel_DEBUG)
229
230 _dotfile = mimebox_file.startswith('.')
231 _blacklisted = mimebox_file.upper().split('.')[-1] in defaults.X2GO_MIMEBOX_EXTENSIONS_BLACKLIST
232 _really_process = bool(not _blacklisted and ((not mimebox_extensions) or [ ext for ext in mimebox_extensions if mimebox_file.upper().endswith('%s' % ext.upper()) ]))
233 if _really_process and not _blacklisted and not _dotfile:
234 mimebox_action.do_process(mimebox_file=mimebox_file,
235 mimebox_dir=parent_thread.mimebox_dir,
236 )
237 elif not _blacklisted and not _dotfile:
238 logger('file extension of MIME box file %s is prohibited by session profile configuration' % mimebox_file, loglevel=log.loglevel_NOTICE)
239 elif _dotfile:
240 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)
241 else:
242 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)
243
244 logger('removing MIME box file %s' % mimebox_file, loglevel=log.loglevel_DEBUG)
245
246 utils.patiently_remove_file(parent_thread.mimebox_dir, mimebox_file)
247 logger('removed print job file %s' % mimebox_file, loglevel=log.loglevel_DEBUG)
248
249 del parent_thread.active_jobs['%s' % mimebox_file]
250 parent_thread.mimebox_history.append(mimebox_file)
251
252
253 if len(parent_thread.mimebox_history) > 100:
254 parent_thread.mimebox_history = parent_thread.mimebox_history[-100:]
255
258 """\
259 For each X2go MIME box job we create a sub-thread that let's
260 the MIME box job be processed in the background.
261
262 As a handler for this class the function L{x2go_mimeboxjob_handler()}
263 is used.
264
265 """
267 """\
268 Construct the X2go MIME box job thread...
269
270 All parameters (**kwargs) are passed through to the constructor
271 of C{threading.Thread()}.
272
273 """
274 threading.Thread.__init__(self, **kwargs)
275 self.daemon = True
276