source: server/lib/gutenbach/server/printer.py @ 34a4e5d

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

Cancelling jobs work

  • Property mode set to 100644
File size: 9.1 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                    self.current_job.play()
134                except IndexError:
135                    self.current_job = None
136                except InvalidJobStateException:
137                    heapq.heappush(self.pending_jobs, self.current_job.id)
138                    self.current_job = None
139                   
140    def complete_job(self):
141        with self.lock:
142            if self.current_job is None:
143                return
144
145            try:
146                if not self.current_job.is_finished:
147                    self.current_job.stop()
148            finally:
149                self.finished_jobs.append(self.current_job)
150                self.current_job = None
151
152    def stop(self):
153        pass
154
155    def get_job(self, job_id):
156        with self.lock:
157            if job_id not in self.jobs:
158                raise InvalidJobException(job_id)
159            job = self.jobs[job_id]
160        return job
161
162    ######################################################################
163    ###                        IPP Attributes                          ###
164    ######################################################################
165
166    @property
167    def printer_uri_supported(self):
168        return ipp.PrinterUriSupported(self.uri)
169
170    @property
171    def uri_authentication_supported(self):
172        return ipp.UriAuthenticationSupported("none")
173
174    @property
175    def uri_security_supported(self):
176        return ipp.UriSecuritySupported("none")
177
178    @property
179    def printer_name(self):
180        return ipp.PrinterName(self.name)
181
182    @property
183    def printer_state(self):
184        return ipp.PrinterState(self.state)
185
186    @property
187    def printer_state_reasons(self):
188        return ipp.PrinterStateReasons("none")
189
190    @property
191    def ipp_versions_supported(self):
192        return ipp.IppVersionsSupported("1.0", "1.1")
193
194    # XXX: We should query ourself for the supported operations
195    @property
196    def operations_supported(self):
197        return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
198
199    @property
200    def charset_configured(self):
201        return ipp.CharsetConfigured("utf-8")
202
203    @property
204    def charset_supported(self):
205        return ipp.CharsetSupported("utf-8")
206
207    @property
208    def natural_language_configured(self):
209        return ipp.NaturalLanguageConfigured("en-us")
210
211    @property
212    def generated_natural_language_supported(self):
213        return ipp.GeneratedNaturalLanguageSupported("en-us")
214
215    @property
216    def document_format_default(self):
217        return ipp.DocumentFormatDefault("application/octet-stream")
218
219    @property
220    def document_format_supported(self):
221        return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
222
223    @property
224    def printer_is_accepting_jobs(self):
225        return ipp.PrinterIsAcceptingJobs(True)
226
227    @property
228    def queued_job_count(self):
229        return ipp.QueuedJobCount(len(self.active_jobs))
230
231    @property
232    def pdl_override_supported(self):
233        return ipp.PdlOverrideSupported("not-attempted")
234
235    @property
236    def printer_up_time(self):
237        return ipp.PrinterUpTime(int(time.time()) - self.time_created)
238
239    @property
240    def compression_supported(self):
241        return ipp.CompressionSupported("none")
242
243    @property
244    def multiple_operation_time_out(self):
245        return ipp.MultipleOperationTimeOut(240)
246
247    @property
248    def multiple_document_jobs_supported(self):
249        return ipp.MultipleDocumentJobsSupported(False)
250
251
252    ######################################################################
253    ###                        IPP Operations                          ###
254    ######################################################################
255
256    def print_job(self):
257        pass
258
259    def validate_job(self):
260        pass
261
262    def get_jobs(self, requesting_user_name="", which_jobs=None):
263        # Filter by the which-jobs attribute
264        if which_jobs is None:
265            which_jobs = "not-completed"
266
267        if which_jobs == "completed":
268            jobs = [self.jobs[job_id] for job_id in self.finished_jobs]
269        elif which_jobs == "not-completed":
270            jobs = [self.jobs[job_id] for job_id in self.active_jobs]
271        else:
272            raise ipp.errors.ClientErrorAttributes(
273                which_jobs, ipp.WhichJobs(which_jobs))
274
275        # Filter by username
276        if requesting_user_name is None:
277            user_jobs = jobs
278        else:
279            user_jobs = [job for job in jobs if job.creator == requesting_user_name]
280       
281        return user_jobs
282
283    def print_uri(self):
284        pass
285
286    def create_job(self, requesting_user_name="", job_name="", job_k_octets=0):
287        job_id = self._next_job_id
288        self._next_job_id += 1
289       
290        job = Job(job_id,
291                  self,
292                  creator=requesting_user_name,
293                  name=job_name,
294                  size=job_k_octets)
295       
296        self.jobs[job_id] = job
297        self.pending_jobs.append(job_id)
298       
299        return job
300
301    def pause_printer(self):
302        pass
303
304    def resume_printer(self):
305        pass
306
307    def get_printer_attributes(self, requested_attributes=None):
308        if requested_attributes is None:
309            requested = self.attributes
310        else:
311            requested = [a for a in self.attributes if a in requested_attributes]
312
313        _attributes = [attr.replace("-", "_") for attr in requested]
314        attributes = [getattr(self, attr) for attr in _attributes]
315        return attributes
316
317    def set_printer_attributes(self):
318        pass
Note: See TracBrowser for help on using the repository browser.