Package x2go :: Module printqueue
[frames] | no frames]

Source Code for Module x2go.printqueue

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2013 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
  4  # 
  5  # Python X2Go is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU Affero General Public License as published by 
  7  # the Free Software Foundation; either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Python X2Go is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU Affero General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU Affero General Public License 
 16  # along with this program; if not, write to the 
 17  # Free Software Foundation, Inc., 
 18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
 19   
 20  """\ 
 21  L{X2GoPrintQueue} sets up a thread that listens for incoming print jobs. 
 22   
 23  For each incoming print job in an X2Go session's spool directory an  
 24  individual thread is started (L{X2GoPrintJob}) that handles the processing  
 25  of the incoming print job. 
 26   
 27  """ 
 28  __NAME__ = 'x2goprintqueue-pylib' 
 29   
 30  # modules 
 31  import os 
 32  import copy 
 33  import threading 
 34  import gevent 
 35   
 36  # Python X2Go modules 
 37  import defaults 
 38  import utils 
 39  import log 
 40   
 41  # we hide the default values from epydoc (that's why we transform them to _UNDERSCORE variables) 
 42  from backends.printing import X2GoClientPrinting as _X2GoClientPrinting 
 43   
 44  from defaults import X2GO_PRINTING_FILENAME as _X2GO_PRINTING_FILENAME 
45 46 47 -class X2GoPrintQueue(threading.Thread):
48 """\ 49 If X2Go printing is supported in a particular L{X2GoSession} instance 50 this class provides a sub-thread for handling incoming X2Go print jobs. 51 52 """ 53 print_action = None 54 55 spooldir = None 56 active_jobs = {} 57 job_history = [] 58
59 - def __init__(self, 60 profile_name='UNKNOWN', 61 session_name='UNKNOWN', 62 spool_dir=None, 63 print_action=None, 64 print_action_args={}, 65 client_instance=None, 66 printing_backend=_X2GoClientPrinting, 67 logger=None, 68 loglevel=log.loglevel_DEFAULT):
69 """\ 70 @param profile_name: name of the session profile this print queue belongs to 71 @type profile_name: C{str} 72 @param spool_dir: local spool directory for incoming print job files 73 @type spool_dir: C{str} 74 @param print_action: name or instance of either of the possible X2Go print action classes 75 @type print_action: C{str} or instance 76 @param print_action_args: depending of the chosen C{print_action} this dictionary may contain different 77 values; the C{print_action_args} will be passed on to the X2Go print action instance constructor, so 78 refer to either of these: L{X2GoPrintActionPDFVIEW}, L{X2GoPrintActionPRINT} et al. 79 @param client_instance: the underlying L{X2GoClient} instance 80 @type client_instance: C{obj} 81 @param printing_backend: the client printing configuration backend class 82 @type printing_backend: C{obj} 83 @param logger: you can pass an L{X2GoLogger} object to the 84 L{X2GoPrintQueue} constructor 85 @type logger: C{obj} 86 @param loglevel: if no L{X2GoLogger} object has been supplied a new one will be 87 constructed with the given loglevel 88 @type loglevel: C{int} 89 90 """ 91 if logger is None: 92 self.logger = log.X2GoLogger(loglevel=loglevel) 93 else: 94 self.logger = copy.deepcopy(logger) 95 self.logger.tag = __NAME__ 96 97 self.profile_name = profile_name 98 self.session_name = session_name 99 self.spool_dir = spool_dir 100 if self.spool_dir: self.spool_dir = os.path.normpath(self.spool_dir) 101 self.client_instance = client_instance 102 self.client_rootdir = client_instance.get_client_rootdir() 103 self.printing_backend = printing_backend 104 if print_action is not None: 105 self.set_print_action(print_action, client_instance=self.client_instance, logger=logger, **print_action_args) 106 threading.Thread.__init__(self) 107 self.daemon = True 108 self._accept_jobs = True
109
110 - def __del__(self):
111 """\ 112 Class destructor. 113 114 """ 115 self.stop_thread()
116
117 - def pause(self):
118 """\ 119 Prevent acceptance of new incoming print jobs. The processing of print 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
127 - def resume(self):
128 """\ 129 Resume operation of the X2Go print spooler and continue accepting new incoming 130 print jobs. 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
137 - def stop_thread(self):
138 """\ 139 Stops this L{X2GoPrintQueue} 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
147 - def _incoming_print_jobs(self):
148 149 if os.path.exists(self.spool_dir): 150 l = os.listdir(self.spool_dir) 151 job_files = [ jf for jf in l if jf.endswith('.ready') ] 152 jobs = [] 153 for _job_file in job_files: 154 j = open(os.path.join(self.spool_dir, _job_file), 'r') 155 content = j.read() 156 try: 157 (pdf_filename, job_title) = content.split('\n')[0:2] 158 except ValueError: 159 pdf_filename = content 160 job_title = 'X2Go Print Job' 161 j.close() 162 jobs.append((_job_file, pdf_filename, job_title)) 163 return [ j for j in jobs if j[1] not in self.active_jobs.keys() ] 164 else: 165 return []
166
167 - def set_print_action(self, print_action, **kwargs):
168 """\ 169 Modify the print action of this L{X2GoPrintQueue} thread during runtime. The 170 change of print action will be valid for the next incoming print job. 171 172 As kwargs you can pass arguments for the print action class to be set. Refer 173 to the class descriptions of L{X2GoPrintActionDIALOG}, L{X2GoPrintActionPDFVIEW}, 174 L{X2GoPrintActionPRINT}, etc. 175 176 @param print_action: new print action to be valid for incoming print jobs 177 @type print_action: C{str} or C{class} 178 @param kwargs: extra options for the specified print action 179 @type kwargs: C{dict} 180 181 """ 182 if print_action in defaults.X2GO_PRINT_ACTIONS.keys(): 183 print_action = defaults.X2GO_PRINT_ACTIONS[print_action] 184 185 if print_action in defaults.X2GO_PRINT_ACTIONS.values(): 186 self.print_action = eval ('printactions.%s(**kwargs)' % print_action)
187
188 - def run(self):
189 """\ 190 Start this L{X2GoPrintQueue} thread... 191 192 """ 193 self.logger('starting print queue thread: %s' % repr(self), loglevel=log.loglevel_DEBUG) 194 195 self._keepalive = True 196 while self._keepalive: 197 198 while self._accept_jobs: 199 200 if self._incoming_print_jobs: 201 202 for _job in self._incoming_print_jobs: 203 self.logger('processing incoming X2Go print job: %s' % _job[1], loglevel=log.loglevel_NOTICE) 204 _new_printjob_thread = X2GoPrintJob(target=x2go_printjob_handler, 205 kwargs={ 206 'job_file': _job[0], 207 'pdf_file': _job[1], 208 'job_title': _job[2], 209 'print_action': self.print_action, 210 'parent_thread': self, 211 'logger': self.logger, 212 } 213 ) 214 self.active_jobs['%s' % _job[1]] = _new_printjob_thread 215 _new_printjob_thread.start() 216 217 gevent.sleep(3) 218 219 gevent.sleep(1)
220
221 222 -def x2go_printjob_handler(job_file=None, pdf_file=None, job_title=None, print_action=None, parent_thread=None, logger=None, ):
223 """\ 224 This function is called as a handler function for each incoming X2Go print job 225 represented by the class L{X2GoPrintJob}. 226 227 The handler function will (re-)read the »printing« configuration file (if no 228 explicit C{print_action} is passed to this function...). It then will 229 execute the C{<print_action>.do_print()} command. 230 231 @param pdf_file: PDF file name as placed in to the X2Go spool directory 232 @type pdf_file: C{str} 233 @param job_title: human readable print job title 234 @type job_title: C{str} 235 @param print_action: an instance of either of the possible C{X2GoPrintActionXXX} classes 236 @type print_action: C{X2GoPrintActionXXX} nstance 237 @param parent_thread: the L{X2GoPrintQueue} thread that actually created this handler's L{X2GoPrintJob} instance 238 @type parent_thread: C{obj} 239 @param logger: the L{X2GoPrintQueue}'s logging instance 240 @type logger: C{obj} 241 242 """ 243 if print_action is None: 244 if parent_thread.client_instance is not None and parent_thread.client_instance.has_custom_client_rootdir: 245 _printing = parent_thread.printing_backend(config_files=[os.path.join(parent_thread.client_instance.get_client_rootdir(), _X2GO_PRINTING_FILENAME)], 246 client_instance=parent_thread.client_instance, 247 logger=logger 248 ) 249 else: 250 _printing = parent_thread.printing_backend(client_instance=parent_thread.client_instance, 251 logger=logger 252 ) 253 254 print_action = _printing.print_action 255 print_action.profile_name = parent_thread.profile_name 256 print_action.session_name = parent_thread.session_name 257 258 logger('action for printing is: %s' % print_action, loglevel=log.loglevel_DEBUG) 259 print_action.do_print(pdf_file=os.path.normpath(os.path.join(parent_thread.spool_dir, pdf_file)), 260 job_title=job_title, 261 spool_dir=parent_thread.spool_dir, 262 ) 263 264 logger('removing print job files for %s' % pdf_file, loglevel=log.loglevel_DEBUG) 265 266 utils.patiently_remove_file(parent_thread.spool_dir, job_file) 267 logger('removed print job file %s' % job_file, loglevel=log.loglevel_DEBUG) 268 utils.patiently_remove_file(parent_thread.spool_dir, pdf_file) 269 logger('removed print pdf file %s' % pdf_file, loglevel=log.loglevel_DEBUG) 270 271 del parent_thread.active_jobs['%s' % pdf_file] 272 parent_thread.job_history.append(pdf_file) 273 274 # in case we print a lot we do not want to risk an endlessly growing 275 # print job history 276 if len(parent_thread.job_history) > 100: 277 parent_thread.job_history = parent_thread.job_history[-100:]
278
279 280 -class X2GoPrintJob(threading.Thread):
281 """\ 282 For each X2Go print job we create a sub-thread that let's 283 the print job be processed in the background. 284 285 As a handler for this class the function L{x2go_printjob_handler()} 286 is used. 287 288 """
289 - def __init__(self, **kwargs):
290 """\ 291 Construct the X2Go print job thread... 292 293 All parameters (**kwargs) are passed through to the constructor 294 of C{threading.Thread()}. 295 296 """ 297 threading.Thread.__init__(self, **kwargs) 298 self.daemon = True
299