source: src/mlx/web.py@ 898:55da787ce6e1

Last change on this file since 898:55da787ce6e1 was 898:55da787ce6e1, checked in by István Váradi <ivaradi@…>, 6 years ago

Aircraft type information (currently DOW, and crew-specific DOW values) are queried via RPC when logging in.

File size: 54.0 KB
Line 
1
2import const
3import util
4from rpc import Registration
5import rpc
6import rpccommon
7
8from common import MAVA_BASE_URL
9from pirep import PIREP
10
11import threading
12import sys
13import urllib
14import urllib2
15import hashlib
16import time
17import datetime
18import codecs
19import traceback
20import xml.sax
21import xmlrpclib
22import HTMLParser
23
24#---------------------------------------------------------------------------------------
25
26## @package mlx.web
27#
28# Web interface.
29#
30# This module implements a thread that can perform (HTTP) requests
31# asynchronously. When the request is performed, a callback is called. The main
32# interface is the \ref Handler class. Each of its functions creates a \ref
33# Request subclass instance and puts it to the request queue. The handler
34# thread then takes the requests one by one, and executes them.
35#
36# This module also defines some data classes the contents of which are
37# retrieved or sent via HTTP. \ref BookedFlight contains data of a flight
38# booked on the MAVA website, \ref Fleet and \ref Plane represents the MAVA
39# fleet and the gates at Ferihegy and \ref NOTAM is a NOTAM.
40
41#---------------------------------------------------------------------------------------
42
43def readline(f):
44 """Read a line from the given file.
45
46 The line is stripped and empty lines are discarded."""
47 while True:
48 line = f.readline()
49 if not line: return ""
50 line = line.strip()
51 if line:
52 return line
53
54#---------------------------------------------------------------------------------------
55
56class BookedFlight(object):
57 """A flight that was booked."""
58 TYPECODE2TYPE = { "736" : const.AIRCRAFT_B736,
59 "73G" : const.AIRCRAFT_B737,
60 "738" : const.AIRCRAFT_B738,
61 "73H" : const.AIRCRAFT_B738C,
62 "732" : const.AIRCRAFT_B732,
63 "733" : const.AIRCRAFT_B733,
64 "734" : const.AIRCRAFT_B734,
65 "735" : const.AIRCRAFT_B735,
66 "DH4" : const.AIRCRAFT_DH8D,
67 "762" : const.AIRCRAFT_B762,
68 "763" : const.AIRCRAFT_B763,
69 "CR2" : const.AIRCRAFT_CRJ2,
70 "F70" : const.AIRCRAFT_F70,
71 "LI2" : const.AIRCRAFT_DC3,
72 "TU3" : const.AIRCRAFT_T134,
73 "TU5" : const.AIRCRAFT_T154,
74 "YK4" : const.AIRCRAFT_YK40,
75 "146" : const.AIRCRAFT_B462,
76 "IL6" : const.AIRCRAFT_IL62 }
77
78 TYPE2TYPECODE = { const.AIRCRAFT_B736 : "736",
79 const.AIRCRAFT_B737 : "73G",
80 const.AIRCRAFT_B738 : "738",
81 const.AIRCRAFT_B738C : "73H",
82 const.AIRCRAFT_B732 : "732",
83 const.AIRCRAFT_B733 : "733",
84 const.AIRCRAFT_B734 : "734",
85 const.AIRCRAFT_B735 : "735",
86 const.AIRCRAFT_DH8D : "DH4",
87 const.AIRCRAFT_B762 : "762",
88 const.AIRCRAFT_B763 : "763",
89 const.AIRCRAFT_CRJ2 : "CR2",
90 const.AIRCRAFT_F70 : "F70",
91 const.AIRCRAFT_DC3 : "LI2",
92 const.AIRCRAFT_T134 : "TU3",
93 const.AIRCRAFT_T154 : "TU5",
94 const.AIRCRAFT_YK40 : "YK4",
95 const.AIRCRAFT_B462 : "146",
96 const.AIRCRAFT_IL62 : "IL6" }
97
98 checkFlightTypes = [ const.AIRCRAFT_B736, const.AIRCRAFT_B737,
99 const.AIRCRAFT_B738, const.AIRCRAFT_DH8D ]
100
101 STATUS_BOOKED = 1
102
103 STATUS_REPORTED = 2
104
105 STATUS_ACCEPTED = 3
106
107 STATUS_REJECTED = 4
108
109 @staticmethod
110 def getDateTime(date, time):
111 """Get a datetime object from the given textual date and time."""
112 return datetime.datetime.strptime(date + " " + time,
113 "%Y-%m-%d %H:%M:%S")
114
115 @staticmethod
116 def forCheckFlight(aircraftType):
117 """Create a booked flight for a check flight with the given aircraft
118 type."""
119 flight = BookedFlight()
120
121 flight.departureICAO = "LHBP"
122 flight.arrivalICAO = "LHBP"
123
124 flight.aircraftType = aircraftType
125 flight.aircraftTypeName = BookedFlight.TYPE2TYPECODE[aircraftType]
126
127 # FIXME: perhaps find one for the type
128 flight.tailNumber = "HA-CHK"
129 flight.callsign = "HA-CHK"
130
131 flight.numPassengers = 0
132 flight.numCrew = 2
133 flight.bagWeight = 0
134 flight.cargoWeight = 0
135 flight.mailWeight = 0
136 flight.route = "DCT"
137
138 t = datetime.datetime.now() + datetime.timedelta(minutes = 20)
139 flight.departureTime = datetime.datetime(t.year, t.month, t.day,
140 t.hour, t.minute)
141 t = flight.departureTime + datetime.timedelta(minutes = 30)
142 flight.arrivalTime = datetime.datetime(t.year, t.month, t.day,
143 t.hour, t.minute)
144
145 return flight
146
147 def __init__(self, id = None):
148 """Construct a booked flight with the given ID."""
149 self.id = id
150
151 @property
152 def status(self):
153 """Get the status of the flight.
154
155 For web-based flights this is always STATUS_BOOKED."""
156 return BookedFlight.STATUS_BOOKED
157
158 def readFromWeb(self, f):
159 """Read the data of the flight from the web via the given file
160 object."""
161 self.callsign = readline(f)
162
163 date = readline(f)
164 print "web.BookedFlight.readFromWeb: date:", date
165 if date=="0000-00-00": date = "0001-01-01"
166
167 self.departureICAO = readline(f)
168 self.arrivalICAO = readline(f)
169
170 self._readAircraftType(f)
171 self.tailNumber = readline(f)
172 self.numPassengers = int(readline(f))
173 self.numCrew = int(readline(f))
174 self.bagWeight = int(readline(f))
175 self.cargoWeight = int(readline(f))
176 self.mailWeight = int(readline(f))
177 self.route = readline(f)
178
179 departureTime = readline(f)
180 self.departureTime = BookedFlight.getDateTime(date, departureTime)
181
182 arrivalTime = readline(f)
183 self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime)
184 if self.arrivalTime<self.departureTime:
185 self.arrivalTime += datetime.timedelta(days = 1)
186
187 if not readline(f)==".NEXT.":
188 raise Exception("Invalid line in flight data")
189
190 def readFromFile(self, f):
191 """Read the data of the flight from a file via the given file
192 object."""
193 date = None
194 departureTime = None
195 arrivalTime = None
196
197 line = f.readline()
198 lineNumber = 0
199 while line:
200 lineNumber += 1
201 line = line.strip()
202
203 hashIndex = line.find("#")
204 if hashIndex>=0: line = line[:hashIndex]
205 if line:
206 equalIndex = line.find("=")
207 lineOK = equalIndex>0
208
209 if lineOK:
210 key = line[:equalIndex].strip()
211 value = line[equalIndex+1:].strip().replace("\:", ":")
212
213 lineOK = key and value
214
215 if lineOK:
216 if key=="callsign": self.callsign = value
217 elif key=="date": date = value
218 elif key=="dep_airport": self.departureICAO = value
219 elif key=="dest_airport": self.arrivalICAO = value
220 elif key=="planecode": self.aircraftType = \
221 self._decodeAircraftType(value)
222 elif key=="planetype": self.aircraftTypeName = value
223 elif key=="tail_nr": self.tailNumber = value
224 elif key=="passenger": self.numPassengers = int(value)
225 elif key=="crew": self.numCrew = int(value)
226 elif key=="bag": self.bagWeight = int(value)
227 elif key=="cargo": self.cargoWeight = int(value)
228 elif key=="mail": self.mailWeight = int(value)
229 elif key=="flight_route": self.route = value
230 elif key=="departure_time": departureTime = value
231 elif key=="arrival_time": arrivalTime = value
232 elif key=="foglalas_id":
233 self.id = None if value=="0" else value
234 else: lineOK = False
235
236 if not lineOK:
237 print "web.BookedFlight.readFromFile: line %d is invalid" % \
238 (lineNumber,)
239
240 line = f.readline()
241
242 if date is not None:
243 if departureTime is not None:
244 self.departureTime = BookedFlight.getDateTime(date,
245 departureTime)
246 if arrivalTime is not None:
247 self.arrivalTime = BookedFlight.getDateTime(date,
248 arrivalTime)
249
250 d = dir(self)
251 for attribute in ["callsign", "departureICAO", "arrivalICAO",
252 "aircraftType", "tailNumber",
253 "numPassengers", "numCrew",
254 "bagWeight", "cargoWeight", "mailWeight",
255 "route", "departureTime", "arrivalTime"]:
256 if attribute not in d:
257 raise Exception("Attribute %s could not be read" % (attribute,))
258
259 if "aircraftTypeName" not in d:
260 self.aircraftTypeName = \
261 BookedFlight.TYPE2TYPECODE[self.aircraftType]
262
263 def setupFromPIREPData(self, pirepData):
264 """Setup the booked flight from the given PIREP data."""
265 bookedFlightData = pirepData["bookedFlight"]
266
267 self.callsign = bookedFlightData["callsign"]
268
269 date = bookedFlightData["date"]
270
271 departureTime = bookedFlightData["departureTime"]
272 self.departureTime = BookedFlight.getDateTime(date, departureTime)
273
274 arrivalTime = bookedFlightData["arrivalTime"]
275 self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime)
276 if self.arrivalTime<self.departureTime:
277 self.arrivalTime += datetime.timedelta(days = 1)
278
279 self.departureICAO = bookedFlightData["departureICAO"]
280 self.arrivalICAO = bookedFlightData["arrivalICAO"]
281
282 self.aircraftType = \
283 self._decodeAircraftType(bookedFlightData["aircraftType"])
284 self.tailNumber = bookedFlightData["tailNumber"]
285 self.numPassengers = int(bookedFlightData["numPassengers"])
286 self.numCrew = int(bookedFlightData["numCrew"])
287 self.bagWeight = int(bookedFlightData["bagWeight"])
288 self.cargoWeight = int(bookedFlightData["cargoWeight"])
289 self.mailWeight = int(bookedFlightData["mailWeight"])
290 self.route = bookedFlightData["route"]
291
292 def writeIntoFile(self, f):
293 """Write the flight into a file."""
294 print >> f, "callsign=%s" % (self.callsign,)
295 date = self.departureTime.date()
296 print >> f, "date=%04d-%02d-%0d" % (date.year, date.month, date.day)
297 print >> f, "dep_airport=%s" % (self.departureICAO,)
298 print >> f, "dest_airport=%s" % (self.arrivalICAO,)
299 print >> f, "planecode=%s" % \
300 (BookedFlight.TYPE2TYPECODE[self.aircraftType],)
301 print >> f, "planetype=%s" % (self.aircraftTypeName,)
302 print >> f, "tail_nr=%s" % (self.tailNumber,)
303 print >> f, "passenger=%d" % (self.numPassengers,)
304 print >> f, "crew=%d" % (self.numCrew,)
305 print >> f, "bag=%d" % (self.bagWeight,)
306 print >> f, "cargo=%d" % (self.cargoWeight,)
307 print >> f, "mail=%d" % (self.mailWeight,)
308 print >> f, "flight_route=%s" % (self.route,)
309 departureTime = self.departureTime
310 print >> f, "departure_time=%02d\\:%02d\\:%02d" % \
311 (departureTime.hour, departureTime.minute, departureTime.second)
312 arrivalTime = self.arrivalTime
313 print >> f, "arrival_time=%02d\\:%02d\\:%02d" % \
314 (arrivalTime.hour, arrivalTime.minute, arrivalTime.second)
315 print >> f, "foglalas_id=%s" % ("0" if self.id is None else self.id,)
316
317 def _readAircraftType(self, f):
318 """Read the aircraft type from the given file."""
319 line = readline(f)
320 typeCode = line[:3]
321 self.aircraftType = self._decodeAircraftType(typeCode)
322 self.aircraftTypeName = line[3:]
323
324 def _decodeAircraftType(self, typeCode):
325 """Decode the aircraft type from the given typeCode."""
326 if typeCode in self.TYPECODE2TYPE:
327 return self.TYPECODE2TYPE[typeCode]
328 else:
329 raise Exception("Invalid aircraft type code: '" + typeCode + "'")
330
331 def __repr__(self):
332 """Get a representation of the flight."""
333 s = "<Flight: %s-%s, %s, %s-%s," % (self.departureICAO,
334 self.arrivalICAO,
335 self.route,
336 self.departureTime, self.arrivalTime)
337 s += " %d %s," % (self.aircraftType, self.tailNumber)
338 s += " pax=%d, crew=%d, bag=%d, cargo=%d, mail=%d" % \
339 (self.numPassengers, self.numCrew,
340 self.bagWeight, self.cargoWeight, self.mailWeight)
341 s += ">"
342 return s
343
344#------------------------------------------------------------------------------
345
346class Plane(rpccommon.Plane):
347 """Information about an airplane in the fleet."""
348 def __init__(self, s):
349 """Build a plane info based on the given string.
350
351 The string consists of three, space-separated fields.
352 The first field is the tail number, the second field is the gate
353 number, the third field is the plane's status as a character."""
354 super(Plane, self).__init__()
355
356 try:
357 words = s.split(" ")
358 tailNumber = words[0]
359 self.tailNumber = tailNumber
360
361 status = words[2] if len(words)>2 else None
362 self._setStatus(status)
363
364 gateNumber = words[1] if len(words)>1 else ""
365 self.gateNumber = gateNumber if gateNumber else None
366
367 except:
368 print >> sys.stderr, "Plane string is invalid: '" + s + "'"
369 self.tailNumber = None
370
371#------------------------------------------------------------------------------
372
373class Fleet(rpccommon.Fleet):
374 """Information about the whole fleet."""
375 def __init__(self, f):
376 """Construct the fleet information by reading the given file object."""
377 super(Fleet, self).__init__()
378
379 while True:
380 line = readline(f)
381 if not line or line == "#END": break
382
383 plane = Plane(line)
384 self._addPlane(plane)
385
386#------------------------------------------------------------------------------
387
388class NOTAM(object):
389 """A NOTAM for an airport."""
390 def __init__(self, ident, basic,
391 begin, notice, end = None, permanent = False,
392 repeatCycle = None):
393 """Construct the NOTAM."""
394 self.ident = ident
395 self.basic = basic
396 self.begin = begin
397 self.notice = notice
398 self.end = end
399 self.permanent = permanent
400 self.repeatCycle = repeatCycle
401
402 def __repr__(self):
403 """Get the representation of the NOTAM."""
404 s = "<NOTAM " + str(self.begin)
405 if self.end:
406 s += " - " + str(self.end)
407 elif self.permanent:
408 s += " - PERMANENT"
409 if self.repeatCycle:
410 s += " (" + self.repeatCycle + ")"
411 s += ": " + self.notice
412 s += ">"
413 return s
414
415 def __str__(self):
416 """Get the string representation of the NOTAM."""
417 s = ""
418 s += str(self.ident) + " " + str(self.basic) + "\n"
419 s += str(self.begin)
420 if self.end is not None:
421 s += " - " + str(self.end)
422 elif self.permanent:
423 s += " - PERMANENT"
424 s += "\n"
425 if self.repeatCycle:
426 s += "Repeat cycle: " + self.repeatCycle + "\n"
427 s += self.notice + "\n"
428 return s
429
430#------------------------------------------------------------------------------
431
432class NOTAMHandler(xml.sax.handler.ContentHandler):
433 """A handler for the NOTAM database."""
434 def __init__(self, airportICAOs):
435 """Construct the handler for the airports with the given ICAO code."""
436 self._notams = {}
437 for icao in airportICAOs:
438 self._notams[icao] = []
439
440 def startElement(self, name, attrs):
441 """Start an element."""
442 if name!="notam" or \
443 "ident" not in attrs or not attrs["ident"] or \
444 "Q" not in attrs or not attrs["Q"] or \
445 "A" not in attrs or not attrs["A"] or \
446 "B" not in attrs or not attrs["B"] or \
447 "E" not in attrs or not attrs["E"]:
448 return
449
450 icao = attrs["A"]
451 if icao not in self._notams:
452 return
453
454 begin = datetime.datetime.strptime(attrs["B"], "%Y-%m-%d %H:%M:%S")
455
456 c = attrs["C"] if "C" in attrs else None
457 end = datetime.datetime.strptime(c, "%Y-%m-%d %H:%M:%S") if c else None
458
459 permanent = attrs["C_flag"]=="PERM" if "C_flag" in attrs else False
460
461 repeatCycle = attrs["D"] if "D" in attrs else None
462
463 self._notams[icao].append(NOTAM(attrs["ident"], attrs["Q"],
464 begin, attrs["E"], end = end,
465 permanent = permanent,
466 repeatCycle = repeatCycle))
467
468 def get(self, icao):
469 """Get the NOTAMs for the given ICAO code."""
470 return self._notams[icao] if icao in self._notams else []
471
472#------------------------------------------------------------------------------
473
474class PilotsWebNOTAMsParser(HTMLParser.HTMLParser):
475 """XML handler for the NOTAM query results on the PilotsWeb website."""
476 def __init__(self):
477 """Construct the handler."""
478 HTMLParser.HTMLParser.__init__(self)
479
480 self._notams = []
481 self._currentNOTAM = ""
482 self._stage = 0
483
484 def handle_starttag(self, name, attrs):
485 """Start an element."""
486 if (self._stage==0 and name=="div" and ("id", "notamRight") in attrs) or \
487 (self._stage==1 and name=="span") or \
488 (self._stage==2 and name=="pre"):
489 self._stage += 1
490 if self._stage==1:
491 self._currentNOTAM = ""
492
493 def handle_data(self, content):
494 """Handle characters"""
495 if self._stage==3:
496 self._currentNOTAM += content
497
498 def handle_endtag(self, name):
499 """End an element."""
500 if (self._stage==3 and name=="pre") or \
501 (self._stage==2 and name=="span") or \
502 (self._stage==1 and name=="div"):
503 self._stage -= 1
504 if self._stage==0:
505 self._processCurrentNOTAM()
506
507 def getNOTAMs(self):
508 """Get the NOTAMs collected"""
509 return self._notams
510
511 def _processCurrentNOTAM(self):
512 """Parse the current NOTAM and append its contents to the list of
513 NOTAMS."""
514 notam = None
515 try:
516 notam = self._parseCurrentNOTAM2()
517 except Exception, e:
518 print "Error parsing current NOTAM: " + str(e)
519
520 if notam is None:
521 print "Could not parse NOTAM: " + self._currentNOTAM
522 if self._currentNOTAM:
523 self._notams.append(self._currentNOTAM + "\n")
524 else:
525 self._notams.append(notam)
526
527 def _parseCurrentNOTAM(self):
528 """Parse the current NOTAM, if possible, and return a NOTAM object."""
529 lines = self._currentNOTAM.splitlines()
530 lines = map(lambda line: line.strip(), lines)
531
532 if len(lines)<4:
533 return None
534
535 if not lines[1].startswith("Q)") or \
536 not lines[2].startswith("A)") or \
537 not (lines[3].startswith("E)") or
538 (lines[3].startswith("D)") and lines[4].startswith("E)"))):
539 return None
540
541 ident = lines[0].split()[0]
542 basic = lines[1][2:].strip()
543
544 words = lines[2].split()
545 if len(words)<4 or words[0]!="A)" or words[2]!="B)":
546 return None
547
548 begin = datetime.datetime.strptime(words[3], "%y%m%d%H%M")
549 end = None
550 permanent = False
551 if words[4]=="C)" and len(words)>=6:
552 if words[5] in ["PERM", "UFN"]:
553 permanent = True
554 else:
555 end = datetime.datetime.strptime(words[5], "%y%m%d%H%M")
556 else:
557 permanent = True
558
559 repeatCycle = None
560 noticeStartIndex = 3
561 if lines[3].startswith("D)"):
562 repeatCycle = lines[3][2:].strip()
563 noticeStartIndex = 4
564
565 notice = ""
566 for index in range(noticeStartIndex, len(lines)):
567 line = lines[index][2:] if index==noticeStartIndex else lines[index]
568 line = line.strip()
569
570 if line.lower().startswith("created:") or \
571 line.lower().startswith("source:"):
572 break
573
574 if notice: notice += " "
575 notice += line
576
577 return NOTAM(ident, basic, begin, notice, end = end,
578 permanent = permanent, repeatCycle = repeatCycle)
579
580 def _parseCurrentNOTAM2(self):
581 """Parse the current NOTAM with a second, more flexible method."""
582 lines = self._currentNOTAM.splitlines()
583 lines = map(lambda line: line.strip(), lines)
584
585 if not lines:
586 return None
587
588 ident = lines[0].split()[0]
589
590 lines = lines[1:]
591 for i in range(0, 2):
592 l = lines[-1].lower()
593 if l.startswith("created:") or l.startswith("source:"):
594 lines = lines[:-1]
595
596 lines = map(lambda line: line.strip(), lines)
597 contents = " ".join(lines).split()
598
599 items = {}
600 for i in ["Q)", "A)", "B)", "C)", "D)", "E)"]:
601 items[i] = ""
602
603 currentItem = None
604 for word in contents:
605 if word in items:
606 currentItem = word
607 elif currentItem in items:
608 s = items[currentItem]
609 if s: s+= " "
610 s += word
611 items[currentItem] = s
612
613 if not items["Q)"] or not items["A)"] or not items["B)"] or \
614 not items["E)"]:
615 return None
616
617 def parseTime(item):
618 try:
619 return datetime.datetime.strptime(item, "%y%m%d%H%M")
620 except ValueError:
621 return datetime.datetime.strptime(item, "%Y%m%d%H%M")
622
623 basic = items["Q)"]
624 begin = parseTime(items["B)"])
625
626 end = None
627 permanent = False
628 if items["C)"]:
629 endItem = items["C)"]
630 if endItem in ["PERM", "UFN"]:
631 permanent = True
632 else:
633 end = parseTime(items["C)"])
634 else:
635 permanent = True
636
637 repeatCycle = None
638 if items["D)"]:
639 repeatCycle = items["D)"]
640
641 notice = items["E)"]
642
643 return NOTAM(ident, basic, begin, notice, end = end,
644 permanent = permanent, repeatCycle = repeatCycle)
645
646#------------------------------------------------------------------------------
647
648class Result(object):
649 """A result object.
650
651 An instance of this filled with the appropriate data is passed to the
652 callback function on each request."""
653
654 def __repr__(self):
655 """Get a representation of the result."""
656 s = "<Result:"
657 for (key, value) in self.__dict__.iteritems():
658 s += " " + key + "=" + unicode(value)
659 s += ">"
660 return s
661
662#------------------------------------------------------------------------------
663
664class Request(object):
665 """Base class for requests.
666
667 It handles any exceptions and the calling of the callback.
668
669 If an exception occurs during processing, the callback is called with
670 the two parameters: a boolean value of False, and the exception object.
671
672 If no exception occurs, the callback is called with True and the return
673 value of the run() function.
674
675 If the callback function throws an exception, that is caught and logged
676 to the debug log."""
677 def __init__(self, callback):
678 """Construct the request."""
679 self._callback = callback
680
681 def perform(self):
682 """Perform the request.
683
684 The object's run() function is called. If it throws an exception,
685 the callback is called with False, and the exception. Otherwise the
686 callback is called with True and the return value of the run()
687 function. Any exceptions thrown by the callback are caught and
688 reported."""
689 try:
690 result = self.run()
691 returned = True
692 except Exception, e:
693 traceback.print_exc()
694 result = e
695 returned = False
696
697 try:
698 self._callback(returned, result)
699 except Exception, e:
700 print >> sys.stderr, "web.Handler.Request.perform: callback throwed an exception: " + util.utf2unicode(str(e))
701 #traceback.print_exc()
702
703#------------------------------------------------------------------------------
704
705class RPCRequest(Request):
706 """Common base class for RPC requests.
707
708 It stores the RPC client received from the handler."""
709 def __init__(self, client, callback):
710 """Construct the request."""
711 super(RPCRequest, self).__init__(callback)
712 self._client = client
713
714#------------------------------------------------------------------------------
715
716class Register(RPCRequest):
717 """A registration request."""
718 def __init__(self, client, callback, registrationData):
719 """Construct the request."""
720 super(Register, self).__init__(client, callback)
721 self._registrationData = registrationData
722
723 def run(self):
724 """Perform the registration."""
725
726 registrationData = self._registrationData
727
728 (resultCode, pilotID) = self._client.register(registrationData)
729 result = Result()
730 result.registered = resultCode==rpc.Client.RESULT_OK
731 if result.registered:
732 result.pilotID = pilotID
733
734 self._client.setCredentials(pilotID, registrationData.password)
735 LoginRPC.setupLoginResult(result, self._client, pilotID,
736 registrationData.password)
737
738 result.invalidData = \
739 resultCode==rpc.Client.RESULT_INVALID_DATA
740 result.emailAlreadyRegistered = \
741 resultCode==rpc.Client.RESULT_EMAIL_ALREADY_REGISTERED
742
743 return result
744
745#------------------------------------------------------------------------------
746
747class Login(Request):
748 """A login request."""
749 iso88592decoder = codecs.getdecoder("iso-8859-2")
750
751 def __init__(self, callback, pilotID, password):
752 """Construct the login request with the given pilot ID and
753 password."""
754 super(Login, self).__init__(callback)
755
756 self._pilotID = pilotID
757 self._password = password
758
759 def run(self):
760 """Perform the login request."""
761 md5 = hashlib.md5()
762 md5.update(self._pilotID)
763 pilotID = md5.hexdigest()
764
765 md5 = hashlib.md5()
766 md5.update(self._password)
767 password = md5.hexdigest()
768
769 url = MAVA_BASE_URL + "/leker2.php?pid=%s&psw=%s" % (pilotID, password)
770
771 result = Result()
772
773 f = urllib2.urlopen(url, timeout = 10.0)
774
775 status = readline(f)
776 result.loggedIn = status == ".OK."
777
778 if result.loggedIn:
779 result.pilotID = self._pilotID
780 result.password = self._password
781 result.rank = "FO"
782 result.flights = []
783
784 result.pilotName = self.iso88592decoder(readline(f))[0]
785 result.exams = readline(f)
786
787 while True:
788 line = readline(f)
789 if not line or line == "#ENDPIREP": break
790
791 flight = BookedFlight(line)
792 flight.readFromWeb(f)
793 result.flights.append(flight)
794
795 result.flights.sort(cmp = lambda flight1, flight2:
796 cmp(flight1.departureTime,
797 flight2.departureTime))
798
799 f.close()
800
801 return result
802
803#------------------------------------------------------------------------------
804
805class LoginRPC(RPCRequest):
806 """An RPC-based login request."""
807 @staticmethod
808 def setupLoginResult(result, client, pilotID, password):
809 """Setup the login result with the given client, pilot ID and
810 password."""
811 loginResult = client.login()
812 result.loggedIn = loginResult is not None
813 if result.loggedIn:
814 result.pilotID = pilotID
815 result.pilotName = loginResult[0]
816 result.rank = loginResult[1]
817 result.types = loginResult[2]
818 result.password = password
819
820 result.aircraftTypes = client.getTypes()
821
822 flights = client.getFlights()
823 result.flights = flights[0]
824 result.reportedFlights = flights[1]
825 result.rejectedFlights = flights[2]
826
827 if result.rank=="STU":
828 reply = client.getEntryExamStatus()
829 result.entryExamPassed = reply[0]
830 result.entryExamLink = reply[1]
831 result.checkFlightStatus = reply[2]
832 if reply[3]:
833 result.rank = "FO"
834
835
836 def __init__(self, client, callback, pilotID, password):
837 """Construct the login request with the given pilot ID and
838 password."""
839 super(LoginRPC, self).__init__(client, callback)
840
841 self._pilotID = pilotID
842 self._password = password
843
844 def run(self):
845 """Perform the login request."""
846 result = Result()
847
848 self._client.setCredentials(self._pilotID, self._password)
849 LoginRPC.setupLoginResult(result, self._client,
850 self._pilotID, self._password)
851
852 return result
853
854#------------------------------------------------------------------------------
855
856class GetEntryExamStatus(RPCRequest):
857 """A request to get the entry exam status."""
858 def __init__(self, client, callback):
859 """Construct the request."""
860 super(GetEntryExamStatus, self).__init__(client, callback)
861
862 def run(self):
863 """Perform the query."""
864 result = Result()
865
866 reply = self._client.getEntryExamStatus()
867
868 result.entryExamPassed = reply[0]
869 result.entryExamLink = reply[1]
870 result.checkFlightStatus = reply[2]
871 result.madeFO = reply[3]
872
873 return result
874
875#------------------------------------------------------------------------------
876
877class GetFleet(Request):
878 """Request to get the fleet from the website."""
879
880 def __init__(self, callback):
881 """Construct the fleet request."""
882 super(GetFleet, self).__init__(callback)
883
884 def run(self):
885 """Perform the login request."""
886 url = MAVA_BASE_URL + "/onlinegates_get.php"
887
888 f = urllib2.urlopen(url, timeout = 10.0)
889 result = Result()
890 result.fleet = Fleet(f)
891 f.close()
892
893 return result
894
895#------------------------------------------------------------------------------
896
897class GetFleetRPC(RPCRequest):
898 """Request to get the fleet from the website using RPC."""
899 def __init__(self, client, callback):
900 """Construct the request with the given client and callback function."""
901 super(GetFleetRPC, self).__init__(client, callback)
902
903 def run(self):
904 """Perform the login request."""
905 result = Result()
906
907 result.fleet = self._client.getFleet()
908
909 return result
910
911#------------------------------------------------------------------------------
912
913class UpdatePlane(Request):
914 """Update the status of one of the planes in the fleet."""
915 def __init__(self, callback, tailNumber, status, gateNumber = None):
916 """Construct the request."""
917 super(UpdatePlane, self).__init__(callback)
918 self._tailNumber = tailNumber
919 self._status = status
920 self._gateNumber = gateNumber
921
922 def run(self):
923 """Perform the plane update."""
924 url = MAVA_BASE_URL + "/onlinegates_set.php"
925
926 status = Plane.status2str(self._status)
927
928 gateNumber = self._gateNumber if self._gateNumber else ""
929
930 data = urllib.urlencode([("lajstrom", self._tailNumber),
931 ("status", status),
932 ("kapu", gateNumber)])
933
934 f = urllib2.urlopen(url, data, timeout = 10.0)
935 line = readline(f)
936
937 result = Result()
938 result.success = line == "OK"
939
940 return result
941
942#------------------------------------------------------------------------------
943
944class UpdatePlaneRPC(RPCRequest):
945 """RPC request to update the status and the position of a plane in the
946 fleet."""
947 def __init__(self, client, callback, tailNumber, status, gateNumber = None):
948 """Construct the request."""
949 super(UpdatePlaneRPC, self).__init__(client, callback)
950 self._tailNumber = tailNumber
951 self._status = status
952 self._gateNumber = gateNumber
953
954 def run(self):
955 """Perform the plane update."""
956 self._client.updatePlane(self._tailNumber, self._status, self._gateNumber)
957
958 # Otherwise an exception is thrown
959 result = Result()
960 result.success = True
961
962 return result
963
964#------------------------------------------------------------------------------
965
966class GetNOTAMs(Request):
967 """Get the NOTAMs from EURoutePro and select the ones we are interested
968 in."""
969 def __init__(self, callback, departureICAO, arrivalICAO):
970 """Construct the request for the given airports."""
971 super(GetNOTAMs, self).__init__(callback)
972 self._departureICAO = departureICAO
973 self._arrivalICAO = arrivalICAO
974
975 def run(self):
976 """Perform the retrieval of the NOTAMs."""
977 departureNOTAMs = self.getPilotsWebNOTAMs(self._departureICAO)
978 arrivalNOTAMs = self.getPilotsWebNOTAMs(self._arrivalICAO)
979
980 icaos = []
981 if not departureNOTAMs: icaos.append(self._departureICAO)
982 if not arrivalNOTAMs: icaos.append(self._arrivalICAO)
983
984 if icaos:
985 xmlParser = xml.sax.make_parser()
986 notamHandler = NOTAMHandler(icaos)
987 xmlParser.setContentHandler(notamHandler)
988
989 url = "http://notams.euroutepro.com/notams.xml"
990
991 f = urllib2.urlopen(url, timeout = 10.0)
992 try:
993 xmlParser.parse(f)
994 finally:
995 f.close()
996
997 for icao in icaos:
998 if icao==self._departureICAO:
999 departureNOTAMs = notamHandler.get(icao)
1000 else:
1001 arrivalNOTAMs = notamHandler.get(icao)
1002
1003 result = Result()
1004 result.departureNOTAMs = departureNOTAMs
1005 result.arrivalNOTAMs = arrivalNOTAMs
1006
1007 return result
1008
1009 def getPilotsWebNOTAMs(self, icao):
1010 """Try to get the NOTAMs from FAA's PilotsWeb site for the given ICAO
1011 code.
1012
1013 Returns a list of PilotsWEBNOTAM objects, or None in case of an error."""
1014 try:
1015 parser = PilotsWebNOTAMsParser()
1016
1017 url = "https://pilotweb.nas.faa.gov/PilotWeb/notamRetrievalByICAOAction.do?method=displayByICAOs&formatType=ICAO&retrieveLocId=%s&reportType=RAW&actionType=notamRetrievalByICAOs" % \
1018 (icao.upper(),)
1019
1020 f = urllib2.urlopen(url, timeout = 10.0)
1021 try:
1022 data = f.read(16384)
1023 while data:
1024 parser.feed(data)
1025 data = f.read(16384)
1026 finally:
1027 f.close()
1028
1029 return parser.getNOTAMs()
1030
1031 except Exception, e:
1032 traceback.print_exc()
1033 print "mlx.web.GetNOTAMs.getPilotsWebNOTAMs: failed to get NOTAMs for '%s': %s" % \
1034 (icao, str(e))
1035 return None
1036
1037#------------------------------------------------------------------------------
1038
1039class GetMETARs(Request):
1040 """Get the METARs from the NOAA website for certain airport ICAOs."""
1041
1042 def __init__(self, callback, airports):
1043 """Construct the request for the given airports."""
1044 super(GetMETARs, self).__init__(callback)
1045 self._airports = airports
1046
1047 def run(self):
1048 """Perform the retrieval opf the METARs."""
1049 url = "http://www.aviationweather.gov/adds/dataserver_current/httpparam?"
1050 data = urllib.urlencode([ ("dataSource" , "metars"),
1051 ("requestType", "retrieve"),
1052 ("format", "csv"),
1053 ("stationString", " ".join(self._airports)),
1054 ("hoursBeforeNow", "24"),
1055 ("mostRecentForEachStation", "constraint")])
1056 url += data
1057 f = urllib2.urlopen(url, timeout = 10.0)
1058 try:
1059 result = Result()
1060 result.metars = {}
1061 for line in iter(f.readline, ""):
1062 if len(line)>5 and line[4]==' ':
1063 icao = line[0:4]
1064 if icao in self._airports:
1065 result.metars[icao] = line.strip().split(",")[0]
1066 finally:
1067 f.close()
1068
1069 return result
1070
1071#------------------------------------------------------------------------------
1072
1073class SendPIREP(Request):
1074 """A request to send a PIREP to the MAVA website."""
1075 _latin2Encoder = codecs.getencoder("iso-8859-2")
1076
1077 def __init__(self, callback, pirep):
1078 """Construct the sending of the PIREP."""
1079 super(SendPIREP, self).__init__(callback)
1080 self._pirep = pirep
1081
1082 def run(self):
1083 """Perform the sending of the PIREP."""
1084 url = MAVA_BASE_URL + "/malevacars.php"
1085
1086 pirep = self._pirep
1087
1088 data = {}
1089 data["acarsdata"] = SendPIREP._latin2Encoder(pirep.getACARSText())[0]
1090
1091 bookedFlight = pirep.bookedFlight
1092 data["foglalas_id"] = bookedFlight.id
1093 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
1094 data["fltnum"] = bookedFlight.callsign
1095 data["depap"] = bookedFlight.departureICAO
1096 data["arrap"] = bookedFlight.arrivalICAO
1097 data["pass"] = str(pirep.numPassengers)
1098 data["crew"] = str(pirep.numCrew)
1099 data["cargo"] = str(pirep.cargoWeight)
1100 data["bag"] = str(pirep.bagWeight)
1101 data["mail"] = str(pirep.mailWeight)
1102
1103 data["flttype"] = pirep.flightTypeText
1104 data["onoff"] = "1" if pirep.online else "0"
1105 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
1106 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
1107 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
1108 pirep.blockTimeStart)
1109 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
1110 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
1111 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
1112 pirep.flightTimeStart)
1113 data["timecomm"] = pirep.getTimeComment()
1114 data["fuel"] = "%.2f" % (pirep.fuelUsed,)
1115 data["dep_rwy"] = pirep.departureRunway
1116 data["arr_rwy"] = pirep.arrivalRunway
1117 data["wea_dep"] = pirep.departureMETAR
1118 data["wea_arr"] = pirep.arrivalMETAR
1119 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
1120 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
1121 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
1122 else:
1123 data["mod_alt"] = ""
1124 data["sid"] = pirep.sid
1125 data["navroute"] = pirep.route
1126 data["star"] = pirep.getSTAR()
1127 data["aprtype"] = pirep.approachType
1128 data["diff"] = "2"
1129 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
1130 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
1131 data["kritika"] = pirep.getRatingText()
1132 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
1133 data["distance"] = "%.3f" % (pirep.flownDistance,)
1134 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
1135
1136 postData = urllib.urlencode(data)
1137 f = urllib2.urlopen(url, postData, timeout = 10.0)
1138 try:
1139 result = Result()
1140 line = f.readline().strip()
1141 print "PIREP result from website:", line
1142 result.success = line=="OK"
1143 result.alreadyFlown = line=="MARVOLT"
1144 result.notAvailable = line=="NOMORE"
1145 finally:
1146 f.close()
1147
1148 return result
1149#------------------------------------------------------------------------------
1150
1151class SendPIREPRPC(RPCRequest):
1152 """A request to send a PIREP to the MAVA website via the RPC interface."""
1153
1154 def __init__(self, client, callback, pirep, update):
1155 """Construct the sending of the PIREP."""
1156 super(SendPIREPRPC, self).__init__(client, callback)
1157 self._pirep = pirep
1158 self._update = update
1159
1160 def run(self):
1161 """Perform the sending of the PIREP."""
1162 pirep = self._pirep
1163 resultCode = self._client.addPIREP(pirep.bookedFlight.id, pirep,
1164 self._update)
1165
1166 result = Result()
1167 result.success = resultCode==rpc.Client.RESULT_OK
1168 result.alreadyFlown = resultCode==rpc.Client.RESULT_FLIGHT_ALREADY_REPORTED
1169 result.notAvailable = resultCode==rpc.Client.RESULT_FLIGHT_NOT_EXISTS
1170
1171 return result
1172
1173#------------------------------------------------------------------------------
1174
1175class SendACARS(Request):
1176 """A request to send an ACARS to the MAVA website."""
1177 _latin2Encoder = codecs.getencoder("iso-8859-2")
1178
1179 def __init__(self, callback, acars):
1180 """Construct the request for the given PIREP."""
1181 super(SendACARS, self).__init__(callback)
1182 self._acars = acars
1183
1184 def run(self):
1185 """Perform the sending of the ACARS."""
1186 print "Sending the online ACARS"
1187
1188 url = MAVA_BASE_URL + "/acars2/acarsonline.php"
1189
1190 acars = self._acars
1191 bookedFlight = acars.bookedFlight
1192
1193 data = {}
1194 data["pid"] = acars.pid
1195 data["pilot"] = SendACARS._latin2Encoder(acars.pilotName)[0]
1196
1197 data["pass"] = str(bookedFlight.numPassengers)
1198 data["callsign"] = bookedFlight.callsign
1199 data["airplane"] = bookedFlight.aircraftTypeName
1200 data["from"] = bookedFlight.departureICAO
1201 data["to"] = bookedFlight.arrivalICAO
1202 data["lajstrom"] = bookedFlight.tailNumber
1203
1204 data["block_time"] = acars.getBlockTimeText()
1205 data["longitude"] = str(acars.state.longitude)
1206 data["latitude"] = str(acars.state.latitude)
1207 data["altitude"] = str(acars.state.altitude)
1208 data["speed"] = str(acars.state.groundSpeed)
1209
1210 data["event"] = acars.getEventText()
1211
1212 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
1213 try:
1214 result = Result()
1215 finally:
1216 f.close()
1217
1218 return result
1219
1220#------------------------------------------------------------------------------
1221
1222class SendACARSRPC(RPCRequest):
1223 """A request to send an ACARS to the MAVA website via JSON-RPC."""
1224 def __init__(self, client, callback, acars):
1225 """Construct the request for the given PIREP."""
1226 super(SendACARSRPC, self).__init__(client, callback)
1227 self._acars = acars
1228
1229 def run(self):
1230 """Perform the sending of the ACARS."""
1231 print "Sending the online ACARS via JSON-RPC"
1232
1233 self._client.updateOnlineACARS(self._acars)
1234 return Result()
1235
1236#------------------------------------------------------------------------------
1237
1238class SendBugReport(Request):
1239 """A request to send a bug report to the project homepage."""
1240 _latin2Encoder = codecs.getencoder("iso-8859-2")
1241
1242 def __init__(self, callback, summary, description, email):
1243 """Construct the request for the given bug report."""
1244 super(SendBugReport, self).__init__(callback)
1245 self._summary = summary
1246 self._description = description
1247 self._email = email
1248
1249 def run(self):
1250 """Perform the sending of the bug report."""
1251 serverProxy = xmlrpclib.ServerProxy("http://mlx.varadiistvan.hu/rpc")
1252
1253 result = Result()
1254 result.success = False
1255
1256 attributes = {}
1257 if self._email:
1258 attributes["reporter"] = self._email
1259
1260 result.ticketID = serverProxy.ticket.create(self._summary, self._description,
1261 attributes, True)
1262 print "Created ticket with ID:", result.ticketID
1263 result.success = True
1264
1265 return result
1266
1267#------------------------------------------------------------------------------
1268
1269class SetCheckFlightPassed(RPCRequest):
1270 """A request to mark the user as one having passed the check flight."""
1271 def __init__(self, client, callback, aircraftType):
1272 """Construct the request for the given type."""
1273 super(SetCheckFlightPassed, self).__init__(client, callback)
1274 self._aircraftType = aircraftType
1275
1276 def run(self):
1277 """Perform the update."""
1278 aircraftType = BookedFlight.TYPE2TYPECODE[self._aircraftType]
1279 self._client.setCheckFlightPassed(aircraftType)
1280 return Result()
1281
1282#------------------------------------------------------------------------------
1283
1284class GetPIREP(RPCRequest):
1285 """A request to retrieve the PIREP of a certain flight."""
1286 def __init__(self, client, callback, flightID):
1287 """Construct the request."""
1288 super(GetPIREP, self).__init__(client, callback)
1289 self._flightID = flightID
1290
1291 def run(self):
1292 """Perform the update."""
1293 result = Result()
1294
1295 pirepData = self._client.getPIREP(self._flightID)
1296 print "pirepData:", pirepData
1297
1298 bookedFlight = BookedFlight(self._flightID)
1299 bookedFlight.setupFromPIREPData(pirepData)
1300
1301 result.pirep = PIREP(None)
1302 result.pirep.setupFromPIREPData(pirepData, bookedFlight)
1303
1304 return result
1305
1306#------------------------------------------------------------------------------
1307
1308class ReflyFlights(RPCRequest):
1309 """A request to mark certain flights for reflying."""
1310 def __init__(self, client, callback, flightIDs):
1311 """Construct the request."""
1312 super(ReflyFlights, self).__init__(client, callback)
1313 self._flightIDs = flightIDs
1314
1315 def run(self):
1316 """Perform the update."""
1317 self._client.reflyFlights(self._flightIDs)
1318 return Result()
1319
1320#------------------------------------------------------------------------------
1321
1322class DeleteFlights(RPCRequest):
1323 """A request to delete certain flights."""
1324 def __init__(self, client, callback, flightIDs):
1325 """Construct the request."""
1326 super(DeleteFlights, self).__init__(client, callback)
1327 self._flightIDs = flightIDs
1328
1329 def run(self):
1330 """Perform the update."""
1331 self._client.deleteFlights(self._flightIDs)
1332 return Result()
1333
1334#------------------------------------------------------------------------------
1335
1336class GetAcceptedFlights(RPCRequest):
1337 """Request to get the accepted flights."""
1338 def __init__(self, client, callback):
1339 """Construct the request with the given client and callback function."""
1340 super(GetAcceptedFlights, self).__init__(client, callback)
1341
1342 def run(self):
1343 """Perform the login request."""
1344 result = Result()
1345
1346 result.flights = self._client.getAcceptedFlights()
1347
1348 return result
1349
1350#------------------------------------------------------------------------------
1351
1352class GetTimetable(RPCRequest):
1353 """Request to get the timetable."""
1354 def __init__(self, client, callback, date, types):
1355 """Construct the request with the given client and callback function."""
1356 super(GetTimetable, self).__init__(client, callback)
1357 self._date = date
1358 self._types = types
1359
1360 def run(self):
1361 """Perform the login request."""
1362 result = Result()
1363
1364 result.flightPairs = self._client.getTimetable(self._date, self._types)
1365
1366 return result
1367
1368#------------------------------------------------------------------------------
1369
1370class BookFlights(RPCRequest):
1371 """Request to book flights."""
1372 def __init__(self, client, callback, flightIDs, date, tailNumber):
1373 """Construct the request with the given client and callback function."""
1374 super(BookFlights, self).__init__(client, callback)
1375 self._flightIDs = flightIDs
1376 self._date = date
1377 self._tailNumber = tailNumber
1378
1379 def run(self):
1380 """Perform the login request."""
1381 result = Result()
1382
1383 result.bookedFlights = self._client.bookFlights(self._flightIDs,
1384 self._date,
1385 self._tailNumber)
1386
1387 return result
1388
1389#------------------------------------------------------------------------------
1390
1391class Handler(threading.Thread):
1392 """The handler for the web services.
1393
1394 It can process one request at a time. The results are passed to a callback
1395 function."""
1396 def __init__(self, config, getCredentialsFn):
1397 """Construct the handler."""
1398 super(Handler, self).__init__()
1399
1400 self._requests = []
1401 self._requestCondition = threading.Condition()
1402
1403 self.daemon = True
1404 self._config = config
1405 self._rpcClient = rpc.Client(getCredentialsFn)
1406 if config.rememberPassword:
1407 self._rpcClient.setCredentials(config.pilotID, config.password)
1408
1409 def register(self, callback, registrationData):
1410 """Enqueue a registration request."""
1411 self._addRequest(Register(self._rpcClient, callback, registrationData))
1412
1413 def login(self, callback, pilotID, password):
1414 """Enqueue a login request."""
1415 request = \
1416 LoginRPC(self._rpcClient, callback, pilotID, password) \
1417 if self._config.useRPC else Login(callback, pilotID, password)
1418
1419 self._addRequest(request)
1420
1421 def getEntryExamStatus(self, callback):
1422 """Get the entry exam status."""
1423 self._addRequest(GetEntryExamStatus(self._rpcClient, callback))
1424
1425 def getFleet(self, callback):
1426 """Enqueue a fleet retrieval request."""
1427 request = \
1428 GetFleetRPC(self._rpcClient, callback,) if self._config.useRPC \
1429 else GetFleet(callback)
1430 self._addRequest(request)
1431
1432 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
1433 """Update the status of the given plane."""
1434 request = \
1435 UpdatePlaneRPC(self._rpcClient, callback,
1436 tailNumber, status, gateNumber) \
1437 if self._config.useRPC \
1438 else UpdatePlane(callback, tailNumber, status, gateNumber)
1439 self._addRequest(request)
1440
1441 def getNOTAMs(self, callback, departureICAO, arrivalICAO):
1442 """Get the NOTAMs for the given two airports."""
1443 self._addRequest(GetNOTAMs(callback, departureICAO, arrivalICAO))
1444
1445 def getMETARs(self, callback, airports):
1446 """Get the METARs for the given airports."""
1447 self._addRequest(GetMETARs(callback, airports))
1448
1449 def sendPIREP(self, callback, pirep, update = False):
1450 """Send the given PIREP."""
1451 request = \
1452 SendPIREPRPC(self._rpcClient, callback, pirep, update) \
1453 if self._config.useRPC else SendPIREP(callback, pirep)
1454 self._addRequest(request)
1455
1456 def sendACARS(self, callback, acars):
1457 """Send the given ACARS"""
1458 request = \
1459 SendACARSRPC(self._rpcClient, callback, acars) if self._config.useRPC \
1460 else SendACARS(callback, acars)
1461 self._addRequest(request)
1462
1463 def sendBugReport(self, callback, summary, description, email):
1464 """Send a bug report with the given data."""
1465 self._addRequest(SendBugReport(callback, summary, description, email))
1466
1467 def setCheckFlightPassed(self, callback, aircraftType):
1468 """Mark the check flight as passed."""
1469 self._addRequest(SetCheckFlightPassed(self._rpcClient,
1470 callback, aircraftType))
1471
1472 def getPIREP(self, callback, flightID):
1473 """Query the PIREP for the given flight."""
1474 self._addRequest(GetPIREP(self._rpcClient, callback, flightID))
1475
1476 def reflyFlights(self, callback, flightIDs):
1477 """Mark the flights with the given IDs for reflying."""
1478 self._addRequest(ReflyFlights(self._rpcClient, callback, flightIDs))
1479
1480 def deleteFlights(self, callback, flightIDs):
1481 """Delete the flights with the given IDs."""
1482 self._addRequest(DeleteFlights(self._rpcClient, callback, flightIDs))
1483
1484 def getAcceptedFlights(self, callback):
1485 """Enqueue a request to get the accepted flights."""
1486 self._addRequest(GetAcceptedFlights(self._rpcClient, callback))
1487
1488 def getTimetable(self, callback, date, types):
1489 """Enqueue a request to get the timetable."""
1490 self._addRequest(GetTimetable(self._rpcClient, callback, date, types))
1491
1492 def bookFlights(self, callback, flightIDs, date, tailNumber):
1493 """Enqueue a request to book some flights."""
1494 self._addRequest(BookFlights(self._rpcClient, callback,
1495 flightIDs, date, tailNumber))
1496
1497 def run(self):
1498 """Process the requests."""
1499 while True:
1500 with self._requestCondition:
1501 while not self._requests:
1502 self._requestCondition.wait()
1503 request = self._requests[0]
1504 del self._requests[0]
1505
1506 request.perform()
1507
1508 def _addRequest(self, request):
1509 """Add the given request to the queue."""
1510 with self._requestCondition:
1511 self._requests.append(request)
1512 self._requestCondition.notify()
1513
1514#------------------------------------------------------------------------------
1515
1516if __name__ == "__main__":
1517 import time
1518
1519 def callback(returned, result):
1520 print returned, unicode(result)
1521
1522 handler = Handler()
1523 handler.start()
1524
1525 #handler.login(callback, "P096", "V5fwj")
1526 #handler.getFleet(callback)
1527 # Plane: HA-LEG home (gate 67)
1528 #handler.updatePlane(callback, "HA-LQC", const.PLANE_AWAY, "72")
1529 #time.sleep(3)
1530 #handler.getFleet(callback)
1531 #time.sleep(3)
1532
1533 #handler.getNOTAMs(callback, "LHBP", "EPWA")
1534 #handler.getMETARs(callback, ["LHBP", "EPWA"])
1535 #time.sleep(5)
1536
1537 handler.updatePlane(callback, "HA-LON", const.PLANE_AWAY, "")
1538 time.sleep(3)
1539
1540#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.