source: server/lib/gutenbach/server/job.py @ a2b0582

no-cups
Last change on this file since a2b0582 was a2b0582, checked in by Isaac Evans <ine@…>, 12 years ago

Added tests for printer

  • Property mode set to 100644
File size: 6.9 KB
Line 
1from .errors import InvalidJobStateException, MissingDataException
2from .player import Player
3from gutenbach.ipp import JobStates as States
4import logging
5import os
6
7# initialize logger
8logger = logging.getLogger(__name__)
9
10class GutenbachJob(object):
11
12    def __init__(self, job_id=None, creator=None, name=None,
13                 priority=None, document=None):
14        """Create an empty Gutenbach job.
15
16        """
17
18        self.player = None
19        self.document = None
20
21        self.id = job_id
22        self.creator = creator
23        self.name = name
24        self.priority = priority
25        self._why_done = None
26
27        if document is not None:
28            self.spool(document)
29
30    def __repr__(self):
31        return str(self)
32
33    def __str__(self):
34        return "<Job %d '%s'>" % (self.id, self.name)
35
36    def __cmp__(self, other):
37        return cmp(self.priority, other.priority)
38
39    ######################################################################
40    ###                          Properties                            ###
41    ######################################################################
42
43    @property
44    def id(self):
45        """Unique job identifier.  Should be a positive integer,
46        except when unassigned, when it defaults to -1.
47       
48        """
49        return self._id
50    @id.setter
51    def id(self, val):
52        try:
53            self._id = max(int(val), -1)
54        except TypeError:
55            self._id = -1
56
57    @property
58    def priority(self):
59        return self._priority
60    @priority.setter
61    def priority(self, val):
62        try:
63            self._priority = max(int(val), 1)
64        except TypeError:
65            self._priority = 1
66
67    @property
68    def creator(self):
69        """The user who created the job; analogous to the IPP
70        requesting-user-name.
71
72        """
73        return self._creator
74    @creator.setter
75    def creator(self, val):
76        if val is None:
77            self._creator = ""
78        else:
79            self._creator = str(val)
80
81    @property
82    def name(self):
83        """The job's name.
84
85        """
86        return self._name
87    @name.setter
88    def name(self, val):
89        if val is None:
90            self._name = ""
91        else:
92            self._name = str(val)
93
94    @property
95    def size(self):
96        """The size of the job in bytes.
97
98        """
99        try:
100            size = os.path.getsize(self.document)
101        except:
102            size = 0
103        return size
104
105    @property
106    def is_valid(self):
107        """Whether the job is ready to be manipulated (spooled,
108        played, etc).  Note that playing the job still requires it to
109        be spooled first.
110
111        """
112        return self.id > 0 and \
113               self.priority > 0
114
115    @property
116    def is_ready(self):
117        """Whether the job is ready to be played.
118
119        """
120        return self.is_valid and \
121               self.player is not None and \
122               not self.player.is_playing and \
123               not self._why_done == "cancelled" and \
124               not self._why_done == "aborted"
125
126    @property
127    def is_playing(self):
128        """Whether the job is currently playing (regardless of whether
129        it's paused).
130
131        """
132        return self.is_valid and \
133               self.player is not None and \
134               self.player.is_playing
135
136    @property
137    def is_paused(self):
138        """Whether the job is currently paused.
139
140        """
141        return self.is_valid and \
142               self.player is not None and \
143               self.player.is_paused       
144
145    @property
146    def is_done(self):
147        return (self.is_valid and \
148                self.player is not None and \
149                self.player.is_done) or \
150                (self._why_done == "cancelled" or \
151                 self._why_done == "aborted")
152
153    @property
154    def state(self):
155        """
156        State transitions are as follows:
157HELD ---> PENDING ---> PROCESSING <--> STOPPED (aka paused)
158             ^              |---> CANCELLED
159             |              |---> ABORTED
160             |              |---> COMPLETE ---|
161             |--------------------------------|
162        """
163        if self.is_ready:
164            state = States.PENDING
165        elif self.is_playing and not self.is_paused:
166            state = States.PROCESSING
167        elif self.is_playing and self.is_paused:
168            state = States.STOPPED
169        elif self.is_done and self._why_done == "completed":
170            state = States.COMPLETE
171        elif self.is_done and self._why_done == "cancelled":
172            state = States.CANCELLED
173        elif self.is_done and self._why_done == "aborted":
174            state = States.ABORTED
175        else:
176            state = States.HELD
177        return state
178
179    ######################################################################
180    ###                            Methods                             ###
181    ######################################################################
182
183    def spool(self, document):
184        if not self.is_valid:
185            raise InvalidJobStateException(self.state)
186        self.document = document.name
187        self.player = Player(document)
188        logger.debug("document for job %d is '%s'" % (self.id, self.document))
189
190    def play(self):
191        """Non-blocking play function.  Sets the job state to
192        PROCESSING.
193
194        Raises
195        ------
196        InvalidJobStateException
197            If the job is not ready to be played.
198
199        """
200       
201        # make sure the job is waiting to be played and that it's
202        # valid
203        if not self.is_ready:
204            raise InvalidJobStateException(self.state)
205       
206        # and set the state to processing if we're good to go
207        logger.info("playing job %s" % str(self))
208
209        def _completed():
210            logger.info("completed job %s" % str(self))
211            self._why_done = "completed"
212        self.player.callback = _completed
213        self.player.start()
214
215    def pause(self):
216        """Non-blocking pause function.  Sets the job state to
217        STOPPED.
218
219        """
220       
221        if not self.is_playing:
222            raise InvalidJobStateException(self.state)
223        self.player.mplayer_pause()
224
225    def cancel(self):
226        def _cancelled():
227            logger.info("cancelled job %s" % str(self))
228            self._why_done = "cancelled"
229
230        if self.is_playing:
231            self.player.callback = _cancelled
232            self.player.mplayer_stop()
233        elif self.is_done and not self._why_done == "cancelled":
234            raise InvalidJobStateException(self.state)
235        else:
236            _cancelled()
237
238    def abort(self):
239        def _aborted():
240            logger.info("aborted job %s" % str(self))
241            self._why_done = "aborted"
242
243        if self.is_playing:
244            self.player.callback = _aborted
245            self.player.mplayer_stop()
246        elif self.is_done and not self._why_done == "aborted":
247            raise InvalidJobStateException(self.state)
248        else:
249            _aborted()
250
251
Note: See TracBrowser for help on using the repository browser.