source: src/mlx/web.py@ 204:6616046534cf

Last change on this file since 204:6616046534cf was 204:6616046534cf, checked in by István Váradi <ivaradi@…>, 12 years ago

Minor fixes, additions to the documents

File size: 33.6 KB
Line 
1# Interface towards the websites used
2
3#------------------------------------------------------------------------------
4
5import const
6import util
7
8import threading
9import sys
10import urllib
11import urllib2
12import hashlib
13import time
14import datetime
15import codecs
16import traceback
17import xml.sax
18
19#---------------------------------------------------------------------------------------
20
21def readline(f):
22 """Read a line from the given file.
23
24 The line is stripped and empty lines are discarded."""
25 while True:
26 line = f.readline()
27 if not line: return ""
28 line = line.strip()
29 if line:
30 return line
31
32#---------------------------------------------------------------------------------------
33
34class BookedFlight(object):
35 """A flight that was booked."""
36 TYPECODE2TYPE = { "736" : const.AIRCRAFT_B736,
37 "73G" : const.AIRCRAFT_B737,
38 "738" : const.AIRCRAFT_B738,
39 "73H" : const.AIRCRAFT_B738C,
40 "733" : const.AIRCRAFT_B733,
41 "734" : const.AIRCRAFT_B734,
42 "735" : const.AIRCRAFT_B735,
43 "DH4" : const.AIRCRAFT_DH8D,
44 "762" : const.AIRCRAFT_B762,
45 "763" : const.AIRCRAFT_B763,
46 "CR2" : const.AIRCRAFT_CRJ2,
47 "F70" : const.AIRCRAFT_F70,
48 "LI2" : const.AIRCRAFT_DC3,
49 "TU3" : const.AIRCRAFT_T134,
50 "TU5" : const.AIRCRAFT_T154,
51 "YK4" : const.AIRCRAFT_YK40 }
52
53 TYPE2TYPECODE = { const.AIRCRAFT_B736 : "736",
54 const.AIRCRAFT_B737 : "73G",
55 const.AIRCRAFT_B738 : "738",
56 const.AIRCRAFT_B738C : "73H",
57 const.AIRCRAFT_B733 : "733",
58 const.AIRCRAFT_B734 : "734",
59 const.AIRCRAFT_B735 : "735",
60 const.AIRCRAFT_DH8D : "DH4",
61 const.AIRCRAFT_B762 : "762",
62 const.AIRCRAFT_B763 : "763",
63 const.AIRCRAFT_CRJ2 : "CR2",
64 const.AIRCRAFT_F70 : "F70",
65 const.AIRCRAFT_DC3 : "LI2",
66 const.AIRCRAFT_T134 : "TU3",
67 const.AIRCRAFT_T154 : "TU5",
68 const.AIRCRAFT_YK40 : "YK4" }
69
70 @staticmethod
71 def getDateTime(date, time):
72 """Get a datetime object from the given textual date and time."""
73 return datetime.datetime.strptime(date + " " + time,
74 "%Y-%m-%d %H:%M:%S")
75
76 def __init__(self, id = None):
77 """Construct a booked flight with the given ID."""
78 self.id = id
79
80 def readFromWeb(self, f):
81 """Read the data of the flight from the web via the given file
82 object."""
83 self.callsign = readline(f)
84
85 date = readline(f)
86 print "web.BookedFlight.readFromWeb: date:", date
87 if date=="0000-00-00": date = "0001-01-01"
88
89 self.departureICAO = readline(f)
90 self.arrivalICAO = readline(f)
91
92 self._readAircraftType(f)
93 self.tailNumber = readline(f)
94 self.numPassengers = int(readline(f))
95 self.numCrew = int(readline(f))
96 self.bagWeight = int(readline(f))
97 self.cargoWeight = int(readline(f))
98 self.mailWeight = int(readline(f))
99 self.route = readline(f)
100
101 departureTime = readline(f)
102 self.departureTime = BookedFlight.getDateTime(date, departureTime)
103
104 arrivalTime = readline(f)
105 self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime)
106
107 if not readline(f)==".NEXT.":
108 raise Exception("Invalid line in flight data")
109
110 def readFromFile(self, f):
111 """Read the data of the flight from a file via the given file
112 object."""
113 date = None
114 departureTime = None
115 arrivalTime = None
116
117 line = f.readline()
118 lineNumber = 0
119 while line:
120 lineNumber += 1
121 line = line.strip()
122
123 hashIndex = line.find("#")
124 if hashIndex>=0: line = line[:hashIndex]
125 if line:
126 equalIndex = line.find("=")
127 lineOK = equalIndex>0
128
129 if lineOK:
130 key = line[:equalIndex].strip()
131 value = line[equalIndex+1:].strip().replace("\:", ":")
132
133 lineOK = key and value
134
135 if lineOK:
136 if key=="callsign": self.callsign = value
137 elif key=="date": date = value
138 elif key=="dep_airport": self.departureICAO = value
139 elif key=="dest_airport": self.arrivalICAO = value
140 elif key=="planecode": self.aircraftType = \
141 self._decodeAircraftType(value)
142 elif key=="tail_nr": self.tailNumber = value
143 elif key=="passenger": self.numPassengers = int(value)
144 elif key=="crew": self.numCrew = int(value)
145 elif key=="bag": self.bagWeight = int(value)
146 elif key=="cargo": self.cargoWeight = int(value)
147 elif key=="mail": self.mailWeight = int(value)
148 elif key=="flight_route": self.route = value
149 elif key=="departure_time": departureTime = value
150 elif key=="arrival_time": arrivalTime = value
151 elif key=="foglalas_id": pass
152 elif key=="planetype": pass
153 else: lineOK = False
154
155 if not lineOK:
156 print "web.BookedFlight.readFromFile: line %d is invalid" % \
157 (lineNumber,)
158
159 line = f.readline()
160
161 if date is not None:
162 if departureTime is not None:
163 self.departureTime = BookedFlight.getDateTime(date,
164 departureTime)
165 if arrivalTime is not None:
166 self.arrivalTime = BookedFlight.getDateTime(date,
167 arrivalTime)
168
169 d = dir(self)
170 for attribute in ["callsign", "departureICAO", "arrivalICAO",
171 "aircraftType", "tailNumber",
172 "numPassengers", "numCrew",
173 "bagWeight", "cargoWeight", "mailWeight",
174 "route", "departureTime", "arrivalTime"]:
175 if attribute not in d:
176 raise Exception("Attribute %s could not be read" % (attribute,))
177
178 def _readAircraftType(self, f):
179 """Read the aircraft type from the given file."""
180 line = readline(f)
181 typeCode = line[:3]
182 self.aircraftType = self._decodeAircraftType(typeCode)
183
184 def _decodeAircraftType(self, typeCode):
185 """Decode the aircraft type from the given typeCode."""
186 if typeCode in self.TYPECODE2TYPE:
187 return self.TYPECODE2TYPE[typeCode]
188 else:
189 raise Exception("Invalid aircraft type code: '" + typeCode + "'")
190
191 def __repr__(self):
192 """Get a representation of the flight."""
193 s = "<Flight: %s-%s, %s, %s-%s," % (self.departureICAO,
194 self.arrivalICAO,
195 self.route,
196 self.departureTime, self.arrivalTime)
197 s += " %d %s," % (self.aircraftType, self.tailNumber)
198 s += " pax=%d, crew=%d, bag=%d, cargo=%d, mail=%d" % \
199 (self.numPassengers, self.numCrew,
200 self.bagWeight, self.cargoWeight, self.mailWeight)
201 s += ">"
202 return s
203
204#------------------------------------------------------------------------------
205
206class Plane(object):
207 """Information about an airplane in the fleet."""
208 def __init__(self, s):
209 """Build a plane info based on the given string.
210
211 The string consists of three, space-separated fields.
212 The first field is the tail number, the second field is the gate
213 number, the third field is the plane's status as a character."""
214 try:
215 words = s.split(" ")
216 tailNumber = words[0]
217 self.tailNumber = tailNumber
218
219 status = words[2] if len(words)>2 else None
220 self.status = const.PLANE_HOME if status=="H" else \
221 const.PLANE_AWAY if status=="A" else \
222 const.PLANE_PARKING if status=="P" else \
223 const.PLANE_UNKNOWN
224
225 gateNumber = words[1] if len(words)>1 else ""
226 self.gateNumber = gateNumber if gateNumber else None
227
228 except:
229 print >> sys.stderr, "Plane string is invalid: '" + s + "'"
230 self.tailNumber = None
231
232 def __repr__(self):
233 """Get the representation of the plane object."""
234 s = "<Plane: %s %s" % (self.tailNumber,
235 "home" if self.status==const.PLANE_HOME else \
236 "away" if self.status==const.PLANE_AWAY else \
237 "parking" if self.status==const.PLANE_PARKING \
238 else "unknown")
239 if self.gateNumber is not None:
240 s += " (gate " + self.gateNumber + ")"
241 s += ">"
242 return s
243
244
245#------------------------------------------------------------------------------
246
247class Fleet(object):
248 """Information about the whole fleet."""
249 def __init__(self, f):
250 """Construct the fleet information by reading the given file object."""
251 self._planes = {}
252 while True:
253 line = readline(f)
254 if not line or line == "#END": break
255
256 plane = Plane(line)
257 if plane.tailNumber is not None:
258 self._planes[plane.tailNumber] = plane
259
260 def isGateConflicting(self, plane):
261 """Check if the gate of the given plane conflicts with another plane's
262 position."""
263 for p in self._planes.itervalues():
264 if p.tailNumber!=plane.tailNumber and \
265 p.status==const.PLANE_HOME and \
266 p.gateNumber==plane.gateNumber:
267 return True
268
269 return False
270
271 def getOccupiedGateNumbers(self):
272 """Get a set containing the numbers of the gates occupied by planes."""
273 gateNumbers = set()
274 for p in self._planes.itervalues():
275 if p.status==const.PLANE_HOME and p.gateNumber:
276 gateNumbers.add(p.gateNumber)
277 return gateNumbers
278
279 def updatePlane(self, tailNumber, status, gateNumber = None):
280 """Update the status of the given plane."""
281 if tailNumber in self._planes:
282 plane = self._planes[tailNumber]
283 plane.status = status
284 plane.gateNumber = gateNumber
285
286 def __iter__(self):
287 """Get an iterator over the planes."""
288 for plane in self._planes.itervalues():
289 yield plane
290
291 def __getitem__(self, tailNumber):
292 """Get the plane with the given tail number.
293
294 If the plane is not in the fleet, None is returned."""
295 return self._planes[tailNumber] if tailNumber in self._planes else None
296
297 def __repr__(self):
298 """Get the representation of the fleet object."""
299 return self._planes.__repr__()
300
301#------------------------------------------------------------------------------
302
303class NOTAM(object):
304 """A NOTAM for an airport."""
305 def __init__(self, begin, notice, end = None, permanent = False,
306 repeatCycle = None):
307 """Construct the NOTAM."""
308 self.begin = begin
309 self.notice = notice
310 self.end = end
311 self.permanent = permanent
312 self.repeatCycle = None
313
314 def __repr__(self):
315 """Get the representation of the NOTAM."""
316 s = "<NOTAM " + str(self.begin)
317 if self.end:
318 s += " - " + str(self.end)
319 elif self.permanent:
320 s += " - PERMANENT"
321 if self.repeatCycle:
322 s += " (" + self.repeatCycle + ")"
323 s += ": " + self.notice
324 s += ">"
325 return s
326
327#------------------------------------------------------------------------------
328
329class NOTAMHandler(xml.sax.handler.ContentHandler):
330 """A handler for the NOTAM database."""
331 def __init__(self, airportICAOs):
332 """Construct the handler for the airports with the given ICAO code."""
333 self._notams = {}
334 for icao in airportICAOs:
335 self._notams[icao] = []
336
337 def startElement(self, name, attrs):
338 """Start an element."""
339 if name!="notam" or \
340 "A" not in attrs or not attrs["A"] or \
341 "B" not in attrs or not attrs["B"] or \
342 "E" not in attrs or not attrs["E"]:
343 return
344
345 icao = attrs["A"]
346 if icao not in self._notams:
347 return
348
349 begin = datetime.datetime.strptime(attrs["B"], "%Y-%m-%d %H:%M:%S")
350
351 c = attrs["C"] if "C" in attrs else None
352 end = datetime.datetime.strptime(c, "%Y-%m-%d %H:%M:%S") if c else None
353
354 permanent = attrs["C_flag"]=="PERM" if "C_flag" in attrs else False
355
356 repeatCycle = attrs["D"] if "D" in attrs else None
357
358 self._notams[icao].append(NOTAM(begin, attrs["E"], end = end,
359 permanent = permanent,
360 repeatCycle = repeatCycle))
361
362 def get(self, icao):
363 """Get the NOTAMs for the given ICAO code."""
364 return self._notams[icao] if icao in self._notams else []
365
366#------------------------------------------------------------------------------
367
368class Result(object):
369 """A result object.
370
371 An instance of this filled with the appropriate data is passed to the
372 callback function on each request."""
373
374 def __repr__(self):
375 """Get a representation of the result."""
376 s = "<Result:"
377 for (key, value) in self.__dict__.iteritems():
378 s += " " + key + "=" + unicode(value)
379 s += ">"
380 return s
381
382#------------------------------------------------------------------------------
383
384class Request(object):
385 """Base class for requests.
386
387 It handles any exceptions and the calling of the callback.
388
389 If an exception occurs during processing, the callback is called with
390 the two parameters: a boolean value of False, and the exception object.
391
392 If no exception occurs, the callback is called with True and the return
393 value of the run() function.
394
395 If the callback function throws an exception, that is caught and logged
396 to the debug log."""
397 def __init__(self, callback):
398 """Construct the request."""
399 self._callback = callback
400
401 def perform(self):
402 """Perform the request.
403
404 The object's run() function is called. If it throws an exception,
405 the callback is called with False, and the exception. Otherwise the
406 callback is called with True and the return value of the run()
407 function. Any exceptions thrown by the callback are caught and
408 reported."""
409 try:
410 result = self.run()
411 returned = True
412 except Exception, e:
413 traceback.print_exc()
414 result = e
415 returned = False
416
417 try:
418 self._callback(returned, result)
419 except Exception, e:
420 print >> sys.stderr, "web.Handler.Request.perform: callback throwed an exception: " + str(e)
421 traceback.print_exc()
422
423#------------------------------------------------------------------------------
424
425class Login(Request):
426 """A login request."""
427 iso88592decoder = codecs.getdecoder("iso-8859-2")
428
429 def __init__(self, callback, pilotID, password, entranceExam):
430 """Construct the login request with the given pilot ID and
431 password."""
432 super(Login, self).__init__(callback)
433
434 self._pilotID = pilotID
435 self._password = password
436 self._entranceExam = entranceExam
437
438 def run(self):
439 """Perform the login request."""
440 md5 = hashlib.md5()
441 md5.update(self._pilotID)
442 pilotID = md5.hexdigest()
443
444 md5 = hashlib.md5()
445 md5.update(self._password)
446 password = md5.hexdigest()
447
448 if self._entranceExam:
449 url = "http://www.virtualairlines.hu/ellenorzo/getflightplan.php?pid=%s" % \
450 (pilotID,)
451 else:
452 url = "http://www.virtualairlines.hu/leker2.php?pid=%s&psw=%s" % \
453 (pilotID, password)
454
455 result = Result()
456 result.entranceExam = self._entranceExam
457
458 f = urllib2.urlopen(url, timeout = 10.0)
459
460 status = readline(f)
461 if self._entranceExam:
462 result.loggedIn = status != "#NOEXAM"
463 else:
464 result.loggedIn = status == ".OK."
465
466 if result.loggedIn:
467 result.pilotID = self._pilotID
468 result.flights = []
469 # FIXME: this may not be the correct behaviour
470 # for an entrance exam, but the website returns
471 # an error
472 if self._entranceExam:
473 result.pilotName = result.pilotID
474 result.exams = ""
475 else:
476 result.pilotName = self.iso88592decoder(readline(f))[0]
477 result.exams = readline(f)
478
479 while True:
480 line = readline(f)
481 if not line or line == "#ENDPIREP": break
482
483 flight = BookedFlight(line)
484 flight.readFromWeb(f)
485 result.flights.append(flight)
486
487 result.flights.sort(cmp = lambda flight1, flight2:
488 cmp(flight1.departureTime,
489 flight2.departureTime))
490
491 f.close()
492
493 return result
494
495#------------------------------------------------------------------------------
496
497class GetFleet(Request):
498 """Request to get the fleet from the website."""
499
500 def __init__(self, callback):
501 """Construct the fleet request."""
502 super(GetFleet, self).__init__(callback)
503
504 def run(self):
505 """Perform the login request."""
506 url = "http://www.virtualairlines.hu/onlinegates_get.php"
507
508 f = urllib2.urlopen(url, timeout = 10.0)
509 result = Result()
510 result.fleet = Fleet(f)
511 f.close()
512
513 return result
514
515#------------------------------------------------------------------------------
516
517class UpdatePlane(Request):
518 """Update the status of one of the planes in the fleet."""
519 def __init__(self, callback, tailNumber, status, gateNumber = None):
520 """Construct the request."""
521 super(UpdatePlane, self).__init__(callback)
522 self._tailNumber = tailNumber
523 self._status = status
524 self._gateNumber = gateNumber
525
526 def run(self):
527 """Perform the plane update."""
528 url = "http://www.virtualairlines.hu/onlinegates_set.php"
529
530 status = "H" if self._status==const.PLANE_HOME else \
531 "A" if self._status==const.PLANE_AWAY else \
532 "P" if self._status==const.PLANE_PARKING else ""
533
534 gateNumber = self._gateNumber if self._gateNumber else ""
535
536 data = urllib.urlencode([("lajstrom", self._tailNumber),
537 ("status", status),
538 ("kapu", gateNumber)])
539
540 f = urllib2.urlopen(url, data, timeout = 10.0)
541 line = readline(f)
542
543 result = Result()
544 result.success = line == "OK"
545
546 return result
547
548#------------------------------------------------------------------------------
549
550class GetNOTAMs(Request):
551 """Get the NOTAMs from EURoutePro and select the ones we are interested
552 in."""
553 def __init__(self, callback, departureICAO, arrivalICAO):
554 """Construct the request for the given airports."""
555 super(GetNOTAMs, self).__init__(callback)
556 self._departureICAO = departureICAO
557 self._arrivalICAO = arrivalICAO
558
559 def run(self):
560 """Perform the retrieval of the NOTAMs."""
561 xmlParser = xml.sax.make_parser()
562 notamHandler = NOTAMHandler([self._departureICAO, self._arrivalICAO])
563 xmlParser.setContentHandler(notamHandler)
564
565 url = "http://notams.euroutepro.com/notams.xml"
566
567 f = urllib2.urlopen(url, timeout = 10.0)
568 try:
569 xmlParser.parse(f)
570 finally:
571 f.close()
572
573 result = Result()
574 result.departureNOTAMs = notamHandler.get(self._departureICAO)
575 result.arrivalNOTAMs = notamHandler.get(self._arrivalICAO)
576
577 return result
578
579#------------------------------------------------------------------------------
580
581class GetMETARs(Request):
582 """Get the METARs from the NOAA website for certain airport ICAOs."""
583
584 def __init__(self, callback, airports):
585 """Construct the request for the given airports."""
586 super(GetMETARs, self).__init__(callback)
587 self._airports = airports
588
589 def run(self):
590 """Perform the retrieval opf the METARs."""
591 url = "http://www.aviationweather.gov/adds/dataserver_current/httpparam?"
592 data = urllib.urlencode([ ("dataSource" , "metars"),
593 ("requestType", "retrieve"),
594 ("format", "csv"),
595 ("stationString", " ".join(self._airports)),
596 ("hoursBeforeNow", "24"),
597 ("mostRecentForEachStation", "constraint")])
598 url += data
599 f = urllib2.urlopen(url, timeout = 10.0)
600 try:
601 result = Result()
602 result.metars = {}
603 for line in iter(f.readline, ""):
604 if len(line)>5 and line[4]==' ':
605 icao = line[0:4]
606 if icao in self._airports:
607 result.metars[icao] = line.strip().split(",")[0]
608 finally:
609 f.close()
610
611 return result
612
613#------------------------------------------------------------------------------
614
615class SendPIREP(Request):
616 """A request to send a PIREP to the MAVA website."""
617 _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
618 const.FLIGHTTYPE_OLDTIMER : "OT",
619 const.FLIGHTTYPE_VIP : "VIP",
620 const.FLIGHTTYPE_CHARTER : "CHARTER" }
621
622 _latin2Encoder = codecs.getencoder("iso-8859-2")
623
624 def __init__(self, callback, pirep):
625 """Construct the request for the given PIREP."""
626 super(SendPIREP, self).__init__(callback)
627 self._pirep = pirep
628
629 def run(self):
630 """Perform the retrieval opf the METARs."""
631 url = "http://www.virtualairlines.hu/malevacars.php"
632
633 pirep = self._pirep
634
635 data = {}
636 data["acarsdata"] = pirep.getACARSText()
637
638 bookedFlight = pirep.bookedFlight
639 data["foglalas_id"] = bookedFlight.id
640 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
641 data["fltnum"] = bookedFlight.callsign
642 data["depap"] = bookedFlight.departureICAO
643 data["arrap"] = bookedFlight.arrivalICAO
644 data["pass"] = str(bookedFlight.numPassengers)
645 data["crew"] = str(bookedFlight.numCrew)
646 data["cargo"] = str(pirep.cargoWeight)
647 data["bag"] = str(bookedFlight.bagWeight)
648 data["mail"] = str(bookedFlight.mailWeight)
649
650 data["flttype"] = SendPIREP._flightTypes[pirep.flightType]
651 data["onoff"] = "1" if pirep.online else "0"
652 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
653 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
654 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
655 pirep.blockTimeStart)
656 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
657 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
658 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
659 pirep.flightTimeStart)
660 data["timecomm"] = pirep.getTimeComment()
661 data["fuel"] = "%.0f" % (pirep.fuelUsed,)
662 data["dep_rwy"] = pirep.departureRunway
663 data["arr_rwy"] = pirep.arrivalRunway
664 data["wea_dep"] = pirep.departureMETAR
665 data["wea_arr"] = pirep.arrivalMETAR
666 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
667 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
668 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
669 else:
670 data["mod_alt"] = ""
671 data["sid"] = pirep.sid
672 data["navroute"] = pirep.route
673 data["star"] = pirep.getSTAR()
674 data["aprtype"] = pirep.approachType
675 data["diff"] = "2"
676 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
677 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
678 data["kritika"] = pirep.getRatingText()
679 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
680 data["distance"] = "%.3f" % (pirep.flownDistance,)
681 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
682
683 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
684 try:
685 result = Result()
686 line = f.readline().strip()
687 print "PIREP result from website:", line
688 result.success = line=="OK"
689 result.alreadyFlown = line=="MARVOLT"
690 result.notAvailable = line=="NOMORE"
691 finally:
692 f.close()
693
694 return result
695
696#------------------------------------------------------------------------------
697
698class SendPIREP(Request):
699 """A request to send a PIREP to the MAVA website."""
700 _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
701 const.FLIGHTTYPE_OLDTIMER : "OT",
702 const.FLIGHTTYPE_VIP : "VIP",
703 const.FLIGHTTYPE_CHARTER : "CHARTER" }
704
705 _latin2Encoder = codecs.getencoder("iso-8859-2")
706
707 def __init__(self, callback, pirep):
708 """Construct the request for the given PIREP."""
709 super(SendPIREP, self).__init__(callback)
710 self._pirep = pirep
711
712 def run(self):
713 """Perform the sending of the PIREP."""
714 url = "http://www.virtualairlines.hu/malevacars.php"
715
716 pirep = self._pirep
717
718 data = {}
719 data["acarsdata"] = pirep.getACARSText()
720
721 bookedFlight = pirep.bookedFlight
722 data["foglalas_id"] = bookedFlight.id
723 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
724 data["fltnum"] = bookedFlight.callsign
725 data["depap"] = bookedFlight.departureICAO
726 data["arrap"] = bookedFlight.arrivalICAO
727 data["pass"] = str(bookedFlight.numPassengers)
728 data["crew"] = str(bookedFlight.numCrew)
729 data["cargo"] = str(pirep.cargoWeight)
730 data["bag"] = str(bookedFlight.bagWeight)
731 data["mail"] = str(bookedFlight.mailWeight)
732
733 data["flttype"] = SendPIREP._flightTypes[pirep.flightType]
734 data["onoff"] = "1" if pirep.online else "0"
735 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
736 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
737 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
738 pirep.blockTimeStart)
739 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
740 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
741 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
742 pirep.flightTimeStart)
743 data["timecomm"] = pirep.getTimeComment()
744 data["fuel"] = "%.0f" % (pirep.fuelUsed,)
745 data["dep_rwy"] = pirep.departureRunway
746 data["arr_rwy"] = pirep.arrivalRunway
747 data["wea_dep"] = pirep.departureMETAR
748 data["wea_arr"] = pirep.arrivalMETAR
749 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
750 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
751 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
752 else:
753 data["mod_alt"] = ""
754 data["sid"] = pirep.sid
755 data["navroute"] = pirep.route
756 data["star"] = pirep.getSTAR()
757 data["aprtype"] = pirep.approachType
758 data["diff"] = "2"
759 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
760 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
761 data["kritika"] = pirep.getRatingText()
762 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
763 data["distance"] = "%.3f" % (pirep.flownDistance,)
764 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
765
766 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
767 try:
768 result = Result()
769 line = f.readline().strip()
770 print "PIREP result from website:", line
771 result.success = line=="OK"
772 result.alreadyFlown = line=="MARVOLT"
773 result.notAvailable = line=="NOMORE"
774 finally:
775 f.close()
776
777 return result
778
779#------------------------------------------------------------------------------
780
781class SendACARS(Request):
782 """A request to send an ACARS to the MAVA website."""
783 _latin2Encoder = codecs.getencoder("iso-8859-2")
784
785 def __init__(self, callback, acars):
786 """Construct the request for the given PIREP."""
787 super(SendACARS, self).__init__(callback)
788 self._acars = acars
789
790 def run(self):
791 """Perform the sending of the ACARS."""
792 print "Sending the online ACARS"
793
794 url = "http://www.virtualairlines.hu/acars2/acarsonline.php"
795
796 acars = self._acars
797 bookedFlight = acars.bookedFlight
798
799 data = {}
800 data["pid"] = acars.pid
801 data["pilot"] = SendACARS._latin2Encoder(acars.pilotName)[0]
802
803 data["pass"] = str(bookedFlight.numPassengers)
804 data["callsign"] = bookedFlight.callsign
805 data["airplane"] = BookedFlight.TYPE2TYPECODE[bookedFlight.aircraftType]
806 data["from"] = bookedFlight.departureICAO
807 data["to"] = bookedFlight.arrivalICAO
808 data["lajstrom"] = bookedFlight.tailNumber
809
810 data["block_time"] = acars.getBlockTimeText()
811 data["longitude"] = str(acars.state.longitude)
812 data["latitude"] = str(acars.state.latitude)
813 data["altitude"] = str(acars.state.altitude)
814 data["speed"] = str(acars.state.groundSpeed)
815
816 data["event"] = acars.getEventText()
817
818 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
819 try:
820 result = Result()
821 finally:
822 f.close()
823
824 return result
825
826#------------------------------------------------------------------------------
827
828class Handler(threading.Thread):
829 """The handler for the web services.
830
831 It can process one request at a time. The results are passed to a callback
832 function."""
833 def __init__(self):
834 """Construct the handler."""
835 super(Handler, self).__init__()
836
837 self._requests = []
838 self._requestCondition = threading.Condition()
839
840 self.daemon = True
841
842 def login(self, callback, pilotID, password, entranceExam = False):
843 """Enqueue a login request."""
844 self._addRequest(Login(callback, pilotID, password, entranceExam))
845
846 def getFleet(self, callback):
847 """Enqueue a fleet retrieval request."""
848 self._addRequest(GetFleet(callback))
849
850 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
851 """Update the status of the given plane."""
852 self._addRequest(UpdatePlane(callback, tailNumber, status, gateNumber))
853
854 def getNOTAMs(self, callback, departureICAO, arrivalICAO):
855 """Get the NOTAMs for the given two airports."""
856 self._addRequest(GetNOTAMs(callback, departureICAO, arrivalICAO))
857
858 def getMETARs(self, callback, airports):
859 """Get the METARs for the given airports."""
860 self._addRequest(GetMETARs(callback, airports))
861
862 def sendPIREP(self, callback, pirep):
863 """Send the given PIREP."""
864 self._addRequest(SendPIREP(callback, pirep))
865
866 def sendACARS(self, callback, acars):
867 """Send the given ACARS"""
868 self._addRequest(SendACARS(callback, acars))
869
870 def run(self):
871 """Process the requests."""
872 while True:
873 with self._requestCondition:
874 while not self._requests:
875 self._requestCondition.wait()
876 request = self._requests[0]
877 del self._requests[0]
878
879 request.perform()
880
881 def _addRequest(self, request):
882 """Add the given request to the queue."""
883 with self._requestCondition:
884 self._requests.append(request)
885 self._requestCondition.notify()
886
887#------------------------------------------------------------------------------
888
889if __name__ == "__main__":
890 import time
891
892 def callback(returned, result):
893 print returned, unicode(result)
894
895 handler = Handler()
896 handler.start()
897
898 #handler.login(callback, "P096", "V5fwj")
899 #handler.getFleet(callback)
900 # Plane: HA-LEG home (gate 67)
901 #handler.updatePlane(callback, "HA-LQC", const.PLANE_AWAY, "72")
902 #time.sleep(3)
903 #handler.getFleet(callback)
904 #time.sleep(3)
905
906 #handler.getNOTAMs(callback, "LHBP", "EPWA")
907 #handler.getMETARs(callback, ["LHBP", "EPWA"])
908 #time.sleep(5)
909
910 handler.updatePlane(callback, "HA-LON", const.PLANE_AWAY, "")
911 time.sleep(3)
912
913#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.