source: src/mlx/web.py@ 139:839016dcd0d1

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

Implemented ACARS sending

File size: 29.2 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.pilotName = self.iso88592decoder(readline(f))[0]
378 result.exams = readline(f)
379 result.flights = []
380
381 while True:
382 line = readline(f)
383 if not line or line == "#ENDPIREP": break
384
385 flight = BookedFlight(line, f)
386 result.flights.append(flight)
387
388 result.flights.sort(cmp = lambda flight1, flight2:
389 cmp(flight1.departureTime,
390 flight2.departureTime))
391
392 f.close()
393
394 return result
395
396#------------------------------------------------------------------------------
397
398class GetFleet(Request):
399 """Request to get the fleet from the website."""
400
401 def __init__(self, callback):
402 """Construct the fleet request."""
403 super(GetFleet, self).__init__(callback)
404
405 def run(self):
406 """Perform the login request."""
407 url = "http://www.virtualairlines.hu/onlinegates_get.php"
408
409 f = urllib2.urlopen(url, timeout = 10.0)
410 result = Result()
411 result.fleet = Fleet(f)
412 f.close()
413
414 return result
415
416#------------------------------------------------------------------------------
417
418class UpdatePlane(Request):
419 """Update the status of one of the planes in the fleet."""
420 def __init__(self, callback, tailNumber, status, gateNumber = None):
421 """Construct the request."""
422 super(UpdatePlane, self).__init__(callback)
423 self._tailNumber = tailNumber
424 self._status = status
425 self._gateNumber = gateNumber
426
427 def run(self):
428 """Perform the plane update."""
429 url = "http://www.virtualairlines.hu/onlinegates_set.php"
430
431 status = "H" if self._status==const.PLANE_HOME else \
432 "A" if self._status==const.PLANE_AWAY else \
433 "P" if self._status==const.PLANE_PARKING else ""
434
435 gateNumber = self._gateNumber if self._gateNumber else ""
436
437 data = urllib.urlencode([("lajstrom", self._tailNumber),
438 ("status", status),
439 ("kapu", gateNumber)])
440
441 f = urllib2.urlopen(url, data, timeout = 10.0)
442 line = readline(f)
443
444 result = Result()
445 result.success = line == "OK"
446
447 return result
448
449#------------------------------------------------------------------------------
450
451class GetNOTAMs(Request):
452 """Get the NOTAMs from EURoutePro and select the ones we are interested
453 in."""
454 def __init__(self, callback, departureICAO, arrivalICAO):
455 """Construct the request for the given airports."""
456 super(GetNOTAMs, self).__init__(callback)
457 self._departureICAO = departureICAO
458 self._arrivalICAO = arrivalICAO
459
460 def run(self):
461 """Perform the retrieval of the NOTAMs."""
462 xmlParser = xml.sax.make_parser()
463 notamHandler = NOTAMHandler([self._departureICAO, self._arrivalICAO])
464 xmlParser.setContentHandler(notamHandler)
465
466 url = "http://notams.euroutepro.com/notams.xml"
467
468 f = urllib2.urlopen(url, timeout = 10.0)
469 try:
470 xmlParser.parse(f)
471 finally:
472 f.close()
473
474 result = Result()
475 result.departureNOTAMs = notamHandler.get(self._departureICAO)
476 result.arrivalNOTAMs = notamHandler.get(self._arrivalICAO)
477
478 return result
479
480#------------------------------------------------------------------------------
481
482class GetMETARs(Request):
483 """Get the METARs from the NOAA website for certain airport ICAOs."""
484
485 def __init__(self, callback, airports):
486 """Construct the request for the given airports."""
487 super(GetMETARs, self).__init__(callback)
488 self._airports = airports
489
490 def run(self):
491 """Perform the retrieval opf the METARs."""
492 url = "http://www.aviationweather.gov/adds/dataserver_current/httpparam?"
493 data = urllib.urlencode([ ("dataSource" , "metars"),
494 ("requestType", "retrieve"),
495 ("format", "csv"),
496 ("stationString", " ".join(self._airports)),
497 ("hoursBeforeNow", "24"),
498 ("mostRecentForEachStation", "constraint")])
499 url += data
500 f = urllib2.urlopen(url, timeout = 10.0)
501 try:
502 result = Result()
503 result.metars = {}
504 for line in iter(f.readline, ""):
505 if len(line)>5 and line[4]==' ':
506 icao = line[0:4]
507 if icao in self._airports:
508 result.metars[icao] = line.strip().split(",")[0]
509 finally:
510 f.close()
511
512 return result
513
514#------------------------------------------------------------------------------
515
516class SendPIREP(Request):
517 """A request to send a PIREP to the MAVA website."""
518 _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
519 const.FLIGHTTYPE_OLDTIMER : "OT",
520 const.FLIGHTTYPE_VIP : "VIP",
521 const.FLIGHTTYPE_CHARTER : "CHARTER" }
522
523 _latin2Encoder = codecs.getencoder("iso-8859-2")
524
525 def __init__(self, callback, pirep):
526 """Construct the request for the given PIREP."""
527 super(SendPIREP, self).__init__(callback)
528 self._pirep = pirep
529
530 def run(self):
531 """Perform the retrieval opf the METARs."""
532 url = "http://www.virtualairlines.hu/malevacars.php"
533
534 pirep = self._pirep
535
536 data = {}
537 data["acarsdata"] = pirep.getACARSText()
538
539 bookedFlight = pirep.bookedFlight
540 data["foglalas_id"] = bookedFlight.id
541 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
542 data["fltnum"] = bookedFlight.callsign
543 data["depap"] = bookedFlight.departureICAO
544 data["arrap"] = bookedFlight.arrivalICAO
545 data["pass"] = str(bookedFlight.numPassengers)
546 data["crew"] = str(bookedFlight.numCrew)
547 data["cargo"] = str(pirep.cargoWeight)
548 data["bag"] = str(bookedFlight.bagWeight)
549 data["mail"] = str(bookedFlight.mailWeight)
550
551 data["flttype"] = SendPIREP._flightTypes[pirep.flightType]
552 data["onoff"] = "1" if pirep.online else "0"
553 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
554 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
555 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
556 pirep.blockTimeStart)
557 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
558 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
559 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
560 pirep.flightTimeStart)
561 data["timecomm"] = pirep.getTimeComment()
562 data["fuel"] = "%.0f" % (pirep.fuelUsed,)
563 data["dep_rwy"] = pirep.departureRunway
564 data["arr_rwy"] = pirep.arrivalRunway
565 data["wea_dep"] = pirep.departureMETAR
566 data["wea_arr"] = pirep.arrivalMETAR
567 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
568 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
569 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
570 else:
571 data["mod_alt"] = ""
572 data["sid"] = pirep.sid
573 data["navroute"] = pirep.route
574 data["star"] = pirep.getSTAR()
575 data["aprtype"] = pirep.approachType
576 data["diff"] = "2"
577 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
578 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
579 data["kritika"] = pirep.getRatingText()
580 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
581 data["distance"] = "%.3f" % (pirep.flownDistance,)
582 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
583
584 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
585 try:
586 result = Result()
587 line = f.readline().strip()
588 print "PIREP result from website:", line
589 result.success = line=="OK"
590 result.alreadyFlown = line=="MARVOLT"
591 result.notAvailable = line=="NOMORE"
592 finally:
593 f.close()
594
595 return result
596
597#------------------------------------------------------------------------------
598
599class SendPIREP(Request):
600 """A request to send a PIREP to the MAVA website."""
601 _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
602 const.FLIGHTTYPE_OLDTIMER : "OT",
603 const.FLIGHTTYPE_VIP : "VIP",
604 const.FLIGHTTYPE_CHARTER : "CHARTER" }
605
606 _latin2Encoder = codecs.getencoder("iso-8859-2")
607
608 def __init__(self, callback, pirep):
609 """Construct the request for the given PIREP."""
610 super(SendPIREP, self).__init__(callback)
611 self._pirep = pirep
612
613 def run(self):
614 """Perform the sending of the PIREP."""
615 url = "http://www.virtualairlines.hu/malevacars.php"
616
617 pirep = self._pirep
618
619 data = {}
620 data["acarsdata"] = pirep.getACARSText()
621
622 bookedFlight = pirep.bookedFlight
623 data["foglalas_id"] = bookedFlight.id
624 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
625 data["fltnum"] = bookedFlight.callsign
626 data["depap"] = bookedFlight.departureICAO
627 data["arrap"] = bookedFlight.arrivalICAO
628 data["pass"] = str(bookedFlight.numPassengers)
629 data["crew"] = str(bookedFlight.numCrew)
630 data["cargo"] = str(pirep.cargoWeight)
631 data["bag"] = str(bookedFlight.bagWeight)
632 data["mail"] = str(bookedFlight.mailWeight)
633
634 data["flttype"] = SendPIREP._flightTypes[pirep.flightType]
635 data["onoff"] = "1" if pirep.online else "0"
636 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
637 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
638 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
639 pirep.blockTimeStart)
640 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
641 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
642 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
643 pirep.flightTimeStart)
644 data["timecomm"] = pirep.getTimeComment()
645 data["fuel"] = "%.0f" % (pirep.fuelUsed,)
646 data["dep_rwy"] = pirep.departureRunway
647 data["arr_rwy"] = pirep.arrivalRunway
648 data["wea_dep"] = pirep.departureMETAR
649 data["wea_arr"] = pirep.arrivalMETAR
650 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
651 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
652 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
653 else:
654 data["mod_alt"] = ""
655 data["sid"] = pirep.sid
656 data["navroute"] = pirep.route
657 data["star"] = pirep.getSTAR()
658 data["aprtype"] = pirep.approachType
659 data["diff"] = "2"
660 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
661 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
662 data["kritika"] = pirep.getRatingText()
663 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
664 data["distance"] = "%.3f" % (pirep.flownDistance,)
665 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
666
667 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
668 try:
669 result = Result()
670 line = f.readline().strip()
671 print "PIREP result from website:", line
672 result.success = line=="OK"
673 result.alreadyFlown = line=="MARVOLT"
674 result.notAvailable = line=="NOMORE"
675 finally:
676 f.close()
677
678 return result
679
680#------------------------------------------------------------------------------
681
682class SendACARS(Request):
683 """A request to send an ACARS to the MAVA website."""
684 _latin2Encoder = codecs.getencoder("iso-8859-2")
685
686 def __init__(self, callback, acars):
687 """Construct the request for the given PIREP."""
688 super(SendACARS, self).__init__(callback)
689 self._acars = acars
690
691 def run(self):
692 """Perform the sending of the ACARS."""
693 url = "http://www.virtualairlines.hu/acars2/acarsonline.php"
694
695 acars = self._acars
696 bookedFlight = acars.bookedFlight
697
698 data = {}
699 data["pid"] = acars.pid
700 data["pilot"] = SendACARS._latin2Encoder(acars.pilotName)[0]
701
702 data["pass"] = str(bookedFlight.numPassengers)
703 data["callsign"] = bookedFlight.callsign
704 data["airplane"] = BookedFlight.TYPE2TYPECODE[bookedFlight.aircraftType]
705 data["from"] = bookedFlight.departureICAO
706 data["to"] = bookedFlight.arrivalICAO
707 data["lajstrom"] = bookedFlight.tailNumber
708
709 data["block_time"] = acars.getBlockTimeText()
710 data["longitude"] = str(acars.state.longitude)
711 data["latitude"] = str(acars.state.latitude)
712 data["altitude"] = str(acars.state.altitude)
713 data["speed"] = str(acars.state.groundSpeed)
714
715 data["event"] = acars.getEventText()
716
717 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
718 try:
719 result = Result()
720 finally:
721 f.close()
722
723 return result
724
725#------------------------------------------------------------------------------
726
727class Handler(threading.Thread):
728 """The handler for the web services.
729
730 It can process one request at a time. The results are passed to a callback
731 function."""
732 def __init__(self):
733 """Construct the handler."""
734 super(Handler, self).__init__()
735
736 self._requests = []
737 self._requestCondition = threading.Condition()
738
739 self.daemon = True
740
741 def login(self, callback, pilotID, password):
742 """Enqueue a login request."""
743 self._addRequest(Login(callback, pilotID, password))
744
745 def getFleet(self, callback):
746 """Enqueue a fleet retrieval request."""
747 self._addRequest(GetFleet(callback))
748
749 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
750 """Update the status of the given plane."""
751 self._addRequest(UpdatePlane(callback, tailNumber, status, gateNumber))
752
753 def getNOTAMs(self, callback, departureICAO, arrivalICAO):
754 """Get the NOTAMs for the given two airports."""
755 self._addRequest(GetNOTAMs(callback, departureICAO, arrivalICAO))
756
757 def getMETARs(self, callback, airports):
758 """Get the METARs for the given airports."""
759 self._addRequest(GetMETARs(callback, airports))
760
761 def sendPIREP(self, callback, pirep):
762 """Send the given PIREP."""
763 self._addRequest(SendPIREP(callback, pirep))
764
765 def sendACARS(self, callback, acars):
766 """Send the given ACARS"""
767 self._addRequest(SendACARS(callback, acars))
768
769 def run(self):
770 """Process the requests."""
771 while True:
772 with self._requestCondition:
773 while not self._requests:
774 self._requestCondition.wait()
775 request = self._requests[0]
776 del self._requests[0]
777
778 request.perform()
779
780 def _addRequest(self, request):
781 """Add the given request to the queue."""
782 with self._requestCondition:
783 self._requests.append(request)
784 self._requestCondition.notify()
785
786#------------------------------------------------------------------------------
787
788if __name__ == "__main__":
789 import time
790
791 def callback(returned, result):
792 print returned, unicode(result)
793
794 handler = Handler()
795 handler.start()
796
797 #handler.login(callback, "P096", "V5fwj")
798 #handler.getFleet(callback)
799 # Plane: HA-LEG home (gate 67)
800 #handler.updatePlane(callback, "HA-LQC", const.PLANE_AWAY, "72")
801 #time.sleep(3)
802 #handler.getFleet(callback)
803 #time.sleep(3)
804
805 #handler.getNOTAMs(callback, "LHBP", "EPWA")
806 handler.getMETARs(callback, ["LHBP", "EPWA"])
807 time.sleep(5)
808
809
810#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.