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

Source Code for Module x2go.printqueue

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2011 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 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 General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU 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  import printactions 
 41   
 42  # we hide the default values from epydoc (that's why we transform them to _UNDERSCORE variables) 
 43  from backends.printing import X2goClientPrinting as _X2goClientPrinting 
 44   
 45  if defaults.X2GOCLIENT_OS != 'Windows': 
 46      from x2go_exceptions import WindowsError 
 47   
 48  from defaults import X2GO_PRINTING_FILENAME as _X2GO_PRINTING_FILENAME 
49 50 51 -class X2goPrintQueue(threading.Thread):
52 """\ 53 If X2go printing is supported in a particular L{X2goSession} instance 54 this class provides a sub-thread for handling incoming X2go print jobs. 55 56 """ 57 print_action = None 58 59 spooldir = None 60 active_jobs = {} 61 job_history = [] 62
63 - def __init__(self, 64 profile_name='UNKNOWN', 65 session_name='UNKNOWN', 66 spool_dir=None, 67 print_action=None, 68 print_action_args={}, 69 client_instance=None, 70 printing_backend=_X2goClientPrinting, 71 logger=None, 72 loglevel=log.loglevel_DEFAULT):
73 """\ 74 @param profile_name: name of the session profile this print queue belongs to 75 @type profile_name: C{str} 76 @param spool_dir: local spool directory for incoming print job files 77 @type spool_dir: C{str} 78 @param print_action: name or instance of either of the possible X2go print action classes 79 @type print_action: C{str} or instance 80 @param print_action_args: depending of the chosen C{print_action} this dictionary may contain different 81 values; the C{print_action_args} will be passed on to the X2go print action instance constructor, so 82 refer to either of these: L{X2goPrintActionPDFVIEW}, L{X2goPrintActionPRINT} et al. 83 @param client_instance: the underlying L{X2goClient} instance 84 @type client_instance: C{instance} 85 @param printing_backend: the client printing configuration backend class 86 @type printing_backend: C{instance} 87 @param logger: you can pass an L{X2goLogger} object to the 88 L{X2goPrintQueue} constructor 89 @type logger: C{instance} 90 @param loglevel: if no L{X2goLogger} object has been supplied a new one will be 91 constructed with the given loglevel 92 @type loglevel: C{int} 93 94 """ 95 if logger is None: 96 self.logger = log.X2goLogger(loglevel=loglevel) 97 else: 98 self.logger = copy.deepcopy(logger) 99 self.logger.tag = __NAME__ 100 101 self.profile_name = profile_name 102 self.session_name = session_name 103 self.spool_dir = spool_dir 104 self.client_instance = client_instance 105 self.client_rootdir = client_instance.get_client_rootdir() 106 self.printing_backend = printing_backend 107 if print_action is not None: 108 self.set_print_action(print_action, client_instance=self.client_instance, logger=logger, **print_action_args) 109 threading.Thread.__init__(self) 110 self.daemon = True 111 self._accept_jobs = True
112
113 - def __del__(self):
114 """\ 115 Class destructor. 116 117 """ 118 self.stop_thread()
119
120 - def pause(self):
121 """\ 122 Prevent acceptance of new incoming print jobs. The processing of print jobs that 123 are currently still active will be completed, though. 124 125 """ 126 if self._accept_jobs == True: 127 self._accept_jobs = False 128 self.logger('paused thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
129
130 - def resume(self):
131 """\ 132 Resume operation of the X2go print spooler and continue accepting new incoming 133 print jobs. 134 135 """ 136 if self._accept_jobs == False: 137 self._accept_jobs = True 138 self.logger('resumed thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
139
140 - def stop_thread(self):
141 """\ 142 Stops this L{X2goPrintQueue} thread completely. 143 144 """ 145 self.pause() 146 self._keepalive = False 147 self.logger('stopping thread: %s' % repr(self), loglevel=log.loglevel_DEBUG)
148 149 @property
150 - def _incoming_print_jobs(self):
151 152 if os.path.exists(self.spool_dir): 153 l = os.listdir(self.spool_dir) 154 job_files = [ jf for jf in l if jf.endswith('.ready') ] 155 jobs = [] 156 for _job_file in job_files: 157 j = open(os.path.join(self.spool_dir, _job_file), 'r') 158 content = j.read() 159 try: 160 (pdf_filename, job_title) = content.split('\n')[0:2] 161 except ValueError: 162 pdf_filename = content 163 job_title = 'X2go Print Job' 164 j.close() 165 jobs.append((_job_file, pdf_filename, job_title)) 166 return [ j for j in jobs if j[1] not in self.active_jobs.keys() ] 167 else: 168 return []
169
170 - def set_print_action(self, print_action, **kwargs):
171 """\ 172 Modify the print action of this L{X2goPrintQueue} thread during runtime. The 173 change of print action will be valid for the next incoming print job. 174 175 As kwargs you can pass arguments for the print action class to be set. Refer 176 to the class descriptions of L{X2goPrintActionDIALOG}, L{X2goPrintActionPDFVIEW}, 177 L{X2goPrintActionPRINT}, etc. 178 179 @param print_action: new print action to be valid for incoming print jobs 180 @type print_action: C{str} or C{class} 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{instance} 239 @param logger: the L{X2goPrintQueue}'s logging instance 240 @type logger: C{instance} 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