source: server/lib/gutenbach/server/printer.py @ eee389a

no-cups
Last change on this file since eee389a was eee389a, checked in by Jessica B. Hamrick <jhamrick@…>, 12 years ago

Better threading model

  • Property mode set to 100644
File size: 9.2 KB
Line 
1from . import InvalidJobException, InvalidPrinterStateException, InvalidJobStateException
2from . import Job
3from gutenbach.ipp import PrinterStates as States
4import gutenbach.ipp as ipp
5import logging
6import time
7import threading
8import heapq
9import traceback
10import sys
11
12
13# initialize logger
14logger = logging.getLogger(__name__)
15
16class GutenbachPrinter(threading.Thread):
17
18    # for IPP
19    attributes = [
20        "printer-uri-supported",
21        "uri-authentication-supported",
22        "uri-security-supported",
23        "printer-name",
24        "printer-state",
25        "printer-state-reasons",
26        "ipp-versions-supported",
27        "operations-supported",
28        "charset-configured",
29        "charset-supported",
30        "natural-language-configured",
31        "generated-natural-language-supported",
32        "document-format-default",
33        "document-format-supported",
34        "printer-is-accepting-jobs",
35        "queued-job-count",
36        "pdl-override-supported",
37        "printer-up-time",
38        "compression-supported",
39        "multiple-operation-time-out",
40        "multiple-document-jobs-supported",
41    ]
42
43    operations = [
44        "print-job",
45        "complete-job",
46        "start-job",
47        "get-job",
48        "get-jobs",
49    ]
50       
51    def __init__(self, name, *args, **kwargs):
52        self.lock = threading.RLock()
53
54        with self.lock:
55            super(GutenbachPrinter, self).__init__(*args, **kwargs)
56           
57            self.name = name
58            self.time_created = int(time.time())
59
60            self.finished_jobs = []
61            self.pending_jobs = []
62            self.current_job = None
63            self.jobs = {}
64
65            self.running = False
66            self.paused = False
67
68            # CUPS ignores jobs with id 0, so we have to start at 1
69            self._next_job_id = 1
70
71    def __repr__(self):
72        return str(self)
73
74    def __str__(self):
75        return "<Printer '%s'>" % self.name
76
77    ######################################################################
78    ###                          Properties                            ###
79    ######################################################################
80
81    @property
82    def uris(self):
83        uris = ["ipp://localhost:8000/printers/" + self.name,
84                "ipp://localhost/printers/" + self.name]
85        return uris
86   
87    @property
88    def uri(self):
89        return self.uris[0]
90
91    @property
92    def state(self):
93        with self.lock:
94            if self.current_job is not None:
95                val = States.PROCESSING
96            elif len(self.pending_jobs) == 0:
97                val = States.IDLE
98            else:
99                val = States.STOPPED
100        return val
101
102    @property
103    def active_jobs(self):
104        with self.lock:
105            jobs = self.pending_jobs[:]
106            if self.current_job is not None:
107                jobs.insert(0, self.current_job.id)
108        return jobs
109
110    ######################################################################
111    ###                            Methods                             ###
112    ######################################################################
113
114    def run(self):
115        self.running = True
116        while self.running:
117            with self.lock:
118                try:
119                    if self.current_job is None:
120                        self.start_job()
121                    elif self.current_job.is_finished:
122                        self.complete_job()
123                except:
124                    logger.fatal(traceback.format_exc())
125                    sys.exit(1)
126            time.sleep(0.1)
127
128    def start_job(self):
129        with self.lock:
130            if self.current_job is None:
131                try:
132                    job_id = heapq.heappop(self.pending_jobs)
133                    self.current_job = self.get_job(job_id)
134                    self.current_job.play()
135                except IndexError:
136                    pass
137                except InvalidJobStateException:
138                    heapq.heappush(self.pending_jobs, self.current_job.id)
139                finally:
140                    self.current_job = None
141                   
142    def complete_job(self):
143        with self.lock:
144            if self.current_job is None:
145                return
146
147            try:
148                if not self.current_job.is_finished:
149                    self.current_job.stop()
150            finally:
151                self.finished_jobs.append(self.current_job)
152                self.current_job = None
153
154    def stop(self):
155        pass
156
157    def get_job(self, job_id):
158        with self.lock:
159            if job_id not in self.jobs:
160                raise InvalidJobException(job_id)
161            job = self.jobs[job_id]
162        return job
163
164    ######################################################################
165    ###                        IPP Attributes                          ###
166    ######################################################################
167
168    @property
169    def printer_uri_supported(self):
170        return ipp.PrinterUriSupported(self.uri)
171
172    @property
173    def uri_authentication_supported(self):
174        return ipp.UriAuthenticationSupported("none")
175
176    @property
177    def uri_security_supported(self):
178        return ipp.UriSecuritySupported("none")
179
180    @property
181    def printer_name(self):
182        return ipp.PrinterName(self.name)
183
184    @property
185    def printer_state(self):
186        return ipp.PrinterState(self.state)
187
188    @property
189    def printer_state_reasons(self):
190        return ipp.PrinterStateReasons("none")
191
192    @property
193    def ipp_versions_supported(self):
194        return ipp.IppVersionsSupported("1.0", "1.1")
195
196    # XXX: We should query ourself for the supported operations
197    @property
198    def operations_supported(self):
199        return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
200
201    @property
202    def charset_configured(self):
203        return ipp.CharsetConfigured("utf-8")
204
205    @property
206    def charset_supported(self):
207        return ipp.CharsetSupported("utf-8")
208
209    @property
210    def natural_language_configured(self):
211        return ipp.NaturalLanguageConfigured("en-us")
212
213    @property
214    def generated_natural_language_supported(self):
215        return ipp.GeneratedNaturalLanguageSupported("en-us")
216
217    @property
218    def document_format_default(self):
219        return ipp.DocumentFormatDefault("application/octet-stream")
220
221    @property
222    def document_format_supported(self):
223        return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
224
225    @property
226    def printer_is_accepting_jobs(self):
227        return ipp.PrinterIsAcceptingJobs(True)
228
229    @property
230    def queued_job_count(self):
231        return ipp.QueuedJobCount(len(self.active_jobs))
232
233    @property
234    def pdl_override_supported(self):
235        return ipp.PdlOverrideSupported("not-attempted")
236
237    @property
238    def printer_up_time(self):
239        return ipp.PrinterUpTime(int(time.time()) - self.time_created)
240
241    @property
242    def compression_supported(self):
243        return ipp.CompressionSupported("none")
244
245    @property
246    def multiple_operation_time_out(self):
247        return ipp.MultipleOperationTimeOut(240)
248
249    @property
250    def multiple_document_jobs_supported(self):
251        return ipp.MultipleDocumentJobsSupported(False)
252
253
254    ######################################################################
255    ###                        IPP Operations                          ###
256    ######################################################################
257
258    def print_job(self):
259        pass
260
261    def validate_job(self):
262        pass
263
264    def get_jobs(self, requesting_user_name="", which_jobs=None):
265        # Filter by the which-jobs attribute
266        if which_jobs is None:
267            jobs = self.jobs.values()
268        elif which_jobs == "completed":
269            jobs = [self.jobs[job_id] for job_id in self.finished_jobs]
270        elif which_jobs == "not-completed":
271            jobs = [self.jobs[job_id] for job_id in self.active_jobs]
272        else:
273            raise ipp.errors.ClientErrorAttributes(
274                which_jobs, ipp.WhichJobs(which_jobs))
275
276        # Filter by username
277        if requesting_user_name is None:
278            user_jobs = jobs
279        else:
280            user_jobs = [job for job in jobs if job.creator == requesting_user_name]
281       
282        return user_jobs
283
284    def print_uri(self):
285        pass
286
287    def create_job(self, requesting_user_name="", job_name="", job_k_octets=0):
288        job_id = self._next_job_id
289        self._next_job_id += 1
290       
291        job = Job(job_id,
292                  self,
293                  creator=requesting_user_name,
294                  name=job_name,
295                  size=job_k_octets)
296       
297        self.jobs[job_id] = job
298        self.pending_jobs.append(job_id)
299       
300        return job
301
302    def pause_printer(self):
303        pass
304
305    def resume_printer(self):
306        pass
307
308    def get_printer_attributes(self, requested_attributes=None):
309        if requested_attributes is None:
310            requested = self.attributes
311        else:
312            requested = [a for a in self.attributes if a in requested_attributes]
313
314        _attributes = [attr.replace("-", "_") for attr in requested]
315        attributes = [getattr(self, attr) for attr in _attributes]
316        return attributes
317
318    def set_printer_attributes(self):
319        pass
Note: See TracBrowser for help on using the repository browser.