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

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

Fix some threading deadlock bugs

  • 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
53        super(GutenbachPrinter, self).__init__(*args, **kwargs)
54       
55        self.name = name
56        self.time_created = int(time.time())
57
58        self.finished_jobs = []
59        self.pending_jobs = []
60        self.current_job = None
61        self.jobs = {}
62
63        self.lock = threading.RLock()
64        self.running = False
65        self.paused = False
66
67        # CUPS ignores jobs with id 0, so we have to start at 1
68        self._next_job_id = 1
69
70    def __repr__(self):
71        return str(self)
72
73    def __str__(self):
74        return "<Printer '%s'>" % self.name
75
76    ######################################################################
77    ###                          Properties                            ###
78    ######################################################################
79
80    @property
81    def uris(self):
82        uris = ["ipp://localhost:8000/printers/" + self.name,
83                "ipp://localhost/printers/" + self.name]
84        return uris
85   
86    @property
87    def uri(self):
88        return self.uris[0]
89
90    @property
91    def state(self):
92        with self.lock:
93            if self.current_job is not None:
94                val = States.PROCESSING
95            elif len(self.pending_jobs) == 0:
96                val = States.IDLE
97            else:
98                val = States.STOPPED
99        return val
100
101    @property
102    def active_jobs(self):
103        with self.lock:
104            jobs = self.pending_jobs[:]
105            if self.current_job is not None:
106                jobs.insert(0, self.current_job.id)
107        return jobs
108
109    ######################################################################
110    ###                            Methods                             ###
111    ######################################################################
112
113    def run(self):
114        self.running = True
115        while self.running:
116            with self.lock:
117                try:
118                    if self.current_job is None:
119                        self.start_job()
120                    elif self.current_job.is_finished:
121                        self.complete_job()
122                except:
123                    logger.fatal(traceback.format_exc())
124                    sys.exit(1)
125            time.sleep(0.1)
126
127    def start_job(self):
128        with self.lock:
129            if self.current_job is None:
130                try:
131                    job_id = heapq.heappop(self.pending_jobs)
132                    self.current_job = self.get_job(job_id)
133                    print "before play"
134                    self.current_job.play()
135                    print "after play"
136                except IndexError:
137                    self.current_job = None
138                except InvalidJobStateException:
139                    heapq.heappush(self.pending_jobs, self.current_job.id)
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.