source: src/mlx/web.py@ 295:7340a9356485

Last change on this file since 295:7340a9356485 was 214:19fb20505b1a, checked in by István Váradi <ivaradi@…>, 12 years ago

Added support for saving a flight into a file

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