source: src/mlx/web.py@ 158:9b9f4da1e8f8

Last change on this file since 158:9b9f4da1e8f8 was 151:a2584357ff6c, checked in by István Váradi <ivaradi@…>, 13 years ago

Added support for saving and loading PIREPs

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