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

Source Code for Module x2go.printqueue

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2014 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  from defaults import X2GO_PRINTING_FILENAME as _X2GO_PRINTING_FILENAME 
 42  from defaults import BACKENDS as _BACKENDS 
43 44 -class X2GoPrintQueue(threading.Thread):
45 """\ 46 If X2Go printing is supported in a particular L{X2GoSession} instance 47 this class provides a sub-thread for handling incoming X2Go print jobs. 48 49 """ 50 print_action = None 51 52 spooldir = None 53 active_jobs = {} 54 job_history = [] 55
56 - def __init__(self, 57 profile_name='UNKNOWN', 58 session_name='UNKNOWN', 59 spool_dir=None, 60 print_action=None, 61 print_action_args={}, 62 client_instance=None, 63 printing_backend=_BACKENDS['X2GoClientPrinting']['default'], 64 logger=None, 65 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 spool_dir: local spool directory for incoming print job files 70 @type spool_dir: C{str} 71 @param print_action: name or instance of either of the possible X2Go print action classes 72 @type print_action: C{str} or instance 73 @param print_action_args: depending of the chosen C{print_action} this dictionary may contain different 74 values; the C{print_action_args} will be passed on to the X2Go print action instance constructor, so 75 refer to either of these: L{X2GoPrintActionPDFVIEW}, L{X2GoPrintActionPRINT} et al. 76 @param client_instance: the underlying L{X2GoClient} instance 77 @type client_instance: C{obj} 78 @param printing_backend: the client printing configuration backend class 79 @type printing_backend: C{obj} 80 @param logger: you can pass an L{X2GoLogger} object to the 81 L{X2GoPrintQueue} constructor 82 @type logger: C{obj} 83 @param loglevel: if no L{X2GoLogger} object has been supplied a new one will be 84 constructed with the given loglevel 85 @type loglevel: C{int} 86 87 """ 88 if logger is None: 89 self.logger = log.X2GoLogger(loglevel=loglevel) 90 else: 91 self.logger = copy.deepcopy(logger) 92 self.logger.tag = __NAME__ 93 94 self.profile_name = profile_name 95 self.session_name = session_name 96 self.spool_dir = spool_dir 97 if self.spool_dir: self.spool_dir = os.path.normpath(self.spool_dir) 98 self.client_instance = client_instance 99 self.client_rootdir = client_instance.get_client_rootdir() 100 self.printing_backend = utils._get_backend_class(printing_backend, "X2GoClientPrinting") 101 if print_action is not None: 102 self.set_print_action(print_action, client_instance=self.client_instance, logger=logger, **print_action_args) 103 threading.Thread.__init__(self) 104 self.daemon = True 105 self._accept_jobs = True
106
107 - def __del__(self):
108 """\ 109 Class destructor. 110 111 """ 112 self.stop_thread()
113
114 - def pause(self):
115 """\ 116 Prevent acceptance of new incoming print jobs. The processing of print jobs that 117 are currently still active will be completed, though. 118 119 """ 120 if self._accept_jobs == True: 121 self._accept_jobs = False 122 self.logger('paused thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
123
124 - def resume(self):
125 """\ 126 Resume operation of the X2Go print spooler and continue accepting new incoming 127 print jobs. 128 129 """ 130 if self._accept_jobs == False: 131 self._accept_jobs = True 132 self.logger('resumed thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
133
134 - def stop_thread(self):
135 """\ 136 Stops this L{X2GoPrintQueue} thread completely. 137 138 """ 139 self.pause() 140 self._keepalive = False 141 self.logger('stopping thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
142 143 @property
144 - def _incoming_print_jobs(self):
145 146 if os.path.exists(self.spool_dir): 147 l = os.listdir(self.spool_dir) 148 job_files = [ jf for jf in l if jf.endswith('.ready') ] 149 jobs = [] 150 for _job_file in job_files: 151 _job_file_handle = open(os.path.join(self.spool_dir, _job_file), 'r') 152 content = _job_file_handle.read() 153 try: 154 (pdf_filename, job_title) = content.split('\n')[0:2] 155 except ValueError: 156 pdf_filename = content 157 job_title = 'X2Go Print Job' 158 _job_file_handle.close() 159 jobs.append((_job_file, pdf_filename, job_title)) 160 return [ j for j in jobs if j[1] not in self.active_jobs.keys() ] 161 else: 162 return []
163
164 - def set_print_action(self, print_action, **kwargs):
165 """\ 166 Modify the print action of this L{X2GoPrintQueue} thread during runtime. The 167 change of print action will be valid for the next incoming print job. 168 169 As kwargs you can pass arguments for the print action class to be set. Refer 170 to the class descriptions of L{X2GoPrintActionDIALOG}, L{X2GoPrintActionPDFVIEW}, 171 L{X2GoPrintActionPRINT}, etc. 172 173 @param print_action: new print action to be valid for incoming print jobs 174 @type print_action: C{str} or C{class} 175 @param kwargs: extra options for the specified print action 176 @type kwargs: C{dict} 177 178 """ 179 if print_action in defaults.X2GO_PRINT_ACTIONS.keys(): 180 print_action = defaults.X2GO_PRINT_ACTIONS[print_action] 181 182 if print_action in defaults.X2GO_PRINT_ACTIONS.values(): 183 self.print_action = eval ('printactions.%s(**kwargs)' % print_action)
184
185 - def run(self):
186 """\ 187 Start this L{X2GoPrintQueue} thread... 188 189 """ 190 self.logger('starting print queue thread: %s' % repr(self), loglevel=log.loglevel_DEBUG) 191 192 self._keepalive = True 193 while self._keepalive: 194 195 while self._accept_jobs: 196 197 if self._incoming_print_jobs: 198 199 for _job in self._incoming_print_jobs: 200 self.logger('processing incoming X2Go print job: %s' % _job[1], loglevel=log.loglevel_NOTICE) 201 _new_printjob_thread = X2GoPrintJob(target=x2go_printjob_handler, 202 kwargs={ 203 'job_file': _job[0], 204 'pdf_file': _job[1], 205 'job_title': _job[2], 206 'print_action': self.print_action, 207 'parent_thread': self, 208 'logger': self.logger, 209 } 210 ) 211 self.active_jobs['%s' % _job[1]] = _new_printjob_thread 212 _new_printjob_thread.start() 213 214 gevent.sleep(3) 215 216 gevent.sleep(1)
217
218 219 -def x2go_printjob_handler(job_file=None, pdf_file=None, job_title=None, print_action=None, parent_thread=None, logger=None, ):
220 """\ 221 This function is called as a handler function for each incoming X2Go print job 222 represented by the class L{X2GoPrintJob}. 223 224 The handler function will (re-)read the »printing« configuration file (if no 225 explicit C{print_action} is passed to this function...). It then will 226 execute the C{<print_action>.do_print()} command. 227 228 @param pdf_file: PDF file name as placed in to the X2Go spool directory 229 @type pdf_file: C{str} 230 @param job_title: human readable print job title 231 @type job_title: C{str} 232 @param print_action: an instance of either of the possible C{X2GoPrintActionXXX} classes 233 @type print_action: C{X2GoPrintActionXXX} nstance 234 @param parent_thread: the L{X2GoPrintQueue} thread that actually created this handler's L{X2GoPrintJob} instance 235 @type parent_thread: C{obj} 236 @param logger: the L{X2GoPrintQueue}'s logging instance 237 @type logger: C{obj} 238 239 """ 240 if print_action is None: 241 if parent_thread.client_instance is not None and parent_thread.client_instance.has_custom_client_rootdir: 242 _printing = parent_thread.printing_backend(config_files=[os.path.join(parent_thread.client_instance.get_client_rootdir(), _X2GO_PRINTING_FILENAME)], 243 client_instance=parent_thread.client_instance, 244 logger=logger 245 ) 246 else: 247 _printing = parent_thread.printing_backend(client_instance=parent_thread.client_instance, 248 logger=logger 249 ) 250 251 print_action = _printing.print_action 252 print_action.profile_name = parent_thread.profile_name 253 print_action.session_name = parent_thread.session_name 254 255 logger('action for printing is: %s' % print_action, loglevel=log.loglevel_DEBUG) 256 print_action.do_print(pdf_file=os.path.normpath(os.path.join(parent_thread.spool_dir, pdf_file)), 257 job_title=job_title, 258 spool_dir=parent_thread.spool_dir, 259 ) 260 261 logger('removing print job files for %s' % pdf_file, loglevel=log.loglevel_DEBUG) 262 263 utils.patiently_remove_file(parent_thread.spool_dir, job_file) 264 logger('removed print job file %s' % job_file, loglevel=log.loglevel_DEBUG) 265 utils.patiently_remove_file(parent_thread.spool_dir, pdf_file) 266 logger('removed print pdf file %s' % pdf_file, loglevel=log.loglevel_DEBUG) 267 268 del parent_thread.active_jobs['%s' % pdf_file] 269 parent_thread.job_history.append(pdf_file) 270 271 # in case we print a lot we do not want to risk an endlessly growing 272 # print job history 273 if len(parent_thread.job_history) > 100: 274 parent_thread.job_history = parent_thread.job_history[-100:]
275
276 277 -class X2GoPrintJob(threading.Thread):
278 """\ 279 For each X2Go print job we create a sub-thread that let's 280 the print job be processed in the background. 281 282 As a handler for this class the function L{x2go_printjob_handler()} 283 is used. 284 285 """
286 - def __init__(self, **kwargs):
287 """\ 288 Construct the X2Go print job thread... 289 290 All parameters (**kwargs) are passed through to the constructor 291 of C{threading.Thread()}. 292 293 """ 294 threading.Thread.__init__(self, **kwargs) 295 self.daemon = True
296