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
RevLine 
[eee389a]1from . import InvalidJobException, InvalidPrinterStateException, InvalidJobStateException
[e58af05]2from . import Job
[b01b6d1]3from gutenbach.ipp import PrinterStates as States
[b2e077a]4import gutenbach.ipp as ipp
5import logging
6import time
[eee389a]7import threading
8import heapq
9import traceback
10import sys
11
[d04a689]12
13# initialize logger
14logger = logging.getLogger(__name__)
[776a659]15
[eee389a]16class GutenbachPrinter(threading.Thread):
[b2e077a]17
[1a63bf7]18    # for IPP
[b2e077a]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",
[f6e2532]38        "compression-supported",
39        "multiple-operation-time-out",
40        "multiple-document-jobs-supported",
[1a63bf7]41    ]
[b2e077a]42
[f6e2532]43    operations = [
44        "print-job",
45        "complete-job",
46        "start-job",
47        "get-job",
48        "get-jobs",
49    ]
50       
[eee389a]51    def __init__(self, name, *args, **kwargs):
52
[d21198f]53        super(GutenbachPrinter, self).__init__(*args, **kwargs)
54       
55        self.name = name
56        self.time_created = int(time.time())
[b2e077a]57
[d21198f]58        self.finished_jobs = []
59        self.pending_jobs = []
60        self.current_job = None
61        self.jobs = {}
[b2e077a]62
[d21198f]63        self.lock = threading.RLock()
64        self.running = False
65        self.paused = False
[776a659]66
[d21198f]67        # CUPS ignores jobs with id 0, so we have to start at 1
68        self._next_job_id = 1
[b01b6d1]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
[eee389a]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
[b01b6d1]108
109    ######################################################################
110    ###                            Methods                             ###
111    ######################################################################
112
[eee389a]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:
[d21198f]135                    self.current_job = None
[eee389a]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
[1a63bf7]151
[b01b6d1]152    def stop(self):
[eee389a]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
[b01b6d1]161
162    ######################################################################
163    ###                        IPP Attributes                          ###
164    ######################################################################
[1a63bf7]165
[b2e077a]166    @property
167    def printer_uri_supported(self):
[793432f]168        return ipp.PrinterUriSupported(self.uri)
[1a63bf7]169
[b2e077a]170    @property
171    def uri_authentication_supported(self):
[793432f]172        return ipp.UriAuthenticationSupported("none")
[b2e077a]173
174    @property
175    def uri_security_supported(self):
[793432f]176        return ipp.UriSecuritySupported("none")
[b2e077a]177
178    @property
179    def printer_name(self):
[793432f]180        return ipp.PrinterName(self.name)
[1a63bf7]181
[b2e077a]182    @property
183    def printer_state(self):
[b01b6d1]184        return ipp.PrinterState(self.state)
[1a63bf7]185
[b2e077a]186    @property
187    def printer_state_reasons(self):
[793432f]188        return ipp.PrinterStateReasons("none")
[b2e077a]189
190    @property
191    def ipp_versions_supported(self):
[793432f]192        return ipp.IppVersionsSupported("1.0", "1.1")
[1a63bf7]193
[f6e2532]194    # XXX: We should query ourself for the supported operations
[b2e077a]195    @property
196    def operations_supported(self):
[793432f]197        return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
[b2e077a]198
199    @property
200    def charset_configured(self):
[793432f]201        return ipp.CharsetConfigured("utf-8")
[b2e077a]202
203    @property
204    def charset_supported(self):
[793432f]205        return ipp.CharsetSupported("utf-8")
[b2e077a]206
207    @property
208    def natural_language_configured(self):
[793432f]209        return ipp.NaturalLanguageConfigured("en-us")
[b2e077a]210
211    @property
212    def generated_natural_language_supported(self):
[793432f]213        return ipp.GeneratedNaturalLanguageSupported("en-us")
[b2e077a]214
215    @property
216    def document_format_default(self):
[793432f]217        return ipp.DocumentFormatDefault("application/octet-stream")
[b2e077a]218
219    @property
220    def document_format_supported(self):
[793432f]221        return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
[b2e077a]222
223    @property
224    def printer_is_accepting_jobs(self):
[793432f]225        return ipp.PrinterIsAcceptingJobs(True)
[b2e077a]226
227    @property
228    def queued_job_count(self):
[793432f]229        return ipp.QueuedJobCount(len(self.active_jobs))
[b2e077a]230
231    @property
232    def pdl_override_supported(self):
[793432f]233        return ipp.PdlOverrideSupported("not-attempted")
[b2e077a]234
235    @property
236    def printer_up_time(self):
[793432f]237        return ipp.PrinterUpTime(int(time.time()) - self.time_created)
[b2e077a]238
239    @property
240    def compression_supported(self):
[793432f]241        return ipp.CompressionSupported("none")
[b2e077a]242
[f6e2532]243    @property
244    def multiple_operation_time_out(self):
[793432f]245        return ipp.MultipleOperationTimeOut(240)
[f6e2532]246
247    @property
248    def multiple_document_jobs_supported(self):
[793432f]249        return ipp.MultipleDocumentJobsSupported(False)
[f6e2532]250
[ee8e6d0]251
[b01b6d1]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:
[34a4e5d]265            which_jobs = "not-completed"
266
267        if which_jobs == "completed":
[b01b6d1]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]
[ee8e6d0]271        else:
[b01b6d1]272            raise ipp.errors.ClientErrorAttributes(
273                which_jobs, ipp.WhichJobs(which_jobs))
[b2e077a]274
[b01b6d1]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]
[ee8e6d0]280       
[b01b6d1]281        return user_jobs
[ee8e6d0]282
[b01b6d1]283    def print_uri(self):
284        pass
285
286    def create_job(self, requesting_user_name="", job_name="", job_k_octets=0):
[eee389a]287        job_id = self._next_job_id
288        self._next_job_id += 1
[ee8e6d0]289       
[b01b6d1]290        job = Job(job_id,
291                  self,
292                  creator=requesting_user_name,
293                  name=job_name,
294                  size=job_k_octets)
295       
[ee8e6d0]296        self.jobs[job_id] = job
[eee389a]297        self.pending_jobs.append(job_id)
[b01b6d1]298       
[ee8e6d0]299        return job
[776a659]300
[b01b6d1]301    def pause_printer(self):
[ee8e6d0]302        pass
[776a659]303
[b01b6d1]304    def resume_printer(self):
305        pass
[776a659]306
[b01b6d1]307    def get_printer_attributes(self, requested_attributes=None):
308        if requested_attributes is None:
309            requested = self.attributes
[e58af05]310        else:
[b01b6d1]311            requested = [a for a in self.attributes if a in requested_attributes]
[b2e077a]312
[b01b6d1]313        _attributes = [attr.replace("-", "_") for attr in requested]
314        attributes = [getattr(self, attr) for attr in _attributes]
315        return attributes
[776a659]316
[b01b6d1]317    def set_printer_attributes(self):
318        pass
Note: See TracBrowser for help on using the repository browser.