from . import const from . import util from .rpc import Registration from . import rpc from . import rpccommon from .common import MAVA_BASE_URL from .pirep import PIREP import threading import sys import urllib.request, urllib.parse, urllib.error import urllib.request, urllib.error, urllib.parse import hashlib import time import re import datetime import codecs import traceback import xml.sax import xmlrpc.client import html.parser #--------------------------------------------------------------------------------------- ## @package mlx.web # # Web interface. # # This module implements a thread that can perform (HTTP) requests # asynchronously. When the request is performed, a callback is called. The main # interface is the \ref Handler class. Each of its functions creates a \ref # Request subclass instance and puts it to the request queue. The handler # thread then takes the requests one by one, and executes them. # # This module also defines some data classes the contents of which are # retrieved or sent via HTTP. \ref BookedFlight contains data of a flight # booked on the MAVA website, \ref Fleet and \ref Plane represents the MAVA # fleet and the gates at Ferihegy and \ref NOTAM is a NOTAM. #--------------------------------------------------------------------------------------- def readline(f): """Read a line from the given file. The line is stripped and empty lines are discarded.""" while True: line = f.readline() if not line: return "" line = line.strip() if line: return line #--------------------------------------------------------------------------------------- class BookedFlight(object): """A flight that was booked.""" TYPECODE2TYPE = { "736" : const.AIRCRAFT_B736, "73G" : const.AIRCRAFT_B737, "738" : const.AIRCRAFT_B738, "73H" : const.AIRCRAFT_B738C, "732" : const.AIRCRAFT_B732, "733" : const.AIRCRAFT_B733, "734" : const.AIRCRAFT_B734, "735" : const.AIRCRAFT_B735, "DH4" : const.AIRCRAFT_DH8D, "762" : const.AIRCRAFT_B762, "763" : const.AIRCRAFT_B763, "CR2" : const.AIRCRAFT_CRJ2, "F70" : const.AIRCRAFT_F70, "LI2" : const.AIRCRAFT_DC3, "TU3" : const.AIRCRAFT_T134, "TU5" : const.AIRCRAFT_T154, "YK4" : const.AIRCRAFT_YK40, "146" : const.AIRCRAFT_B462 } TYPE2TYPECODE = { const.AIRCRAFT_B736 : "736", const.AIRCRAFT_B737 : "73G", const.AIRCRAFT_B738 : "738", const.AIRCRAFT_B738C : "73H", const.AIRCRAFT_B732 : "732", const.AIRCRAFT_B733 : "733", const.AIRCRAFT_B734 : "734", const.AIRCRAFT_B735 : "735", const.AIRCRAFT_DH8D : "DH4", const.AIRCRAFT_B762 : "762", const.AIRCRAFT_B763 : "763", const.AIRCRAFT_CRJ2 : "CR2", const.AIRCRAFT_F70 : "F70", const.AIRCRAFT_DC3 : "LI2", const.AIRCRAFT_T134 : "TU3", const.AIRCRAFT_T154 : "TU5", const.AIRCRAFT_YK40 : "YK4", const.AIRCRAFT_B462 : "146" } checkFlightTypes = [ const.AIRCRAFT_B736, const.AIRCRAFT_B737, const.AIRCRAFT_B738, const.AIRCRAFT_DH8D ] STATUS_BOOKED = 1 STATUS_REPORTED = 2 STATUS_ACCEPTED = 3 STATUS_REJECTED = 4 @staticmethod def getDateTime(date, time): """Get a datetime object from the given textual date and time.""" return datetime.datetime.strptime(date + " " + time, "%Y-%m-%d %H:%M:%S") @staticmethod def forCheckFlight(aircraftType): """Create a booked flight for a check flight with the given aircraft type.""" flight = BookedFlight() flight.departureICAO = "LHBP" flight.arrivalICAO = "LHBP" flight.aircraftType = aircraftType flight.aircraftTypeName = BookedFlight.TYPE2TYPECODE[aircraftType] # FIXME: perhaps find one for the type flight.tailNumber = "HA-CHK" flight.callsign = "HA-CHK" flight.numPassengers = 0 flight.numCrew = 2 flight.bagWeight = 0 flight.cargoWeight = 0 flight.mailWeight = 0 flight.route = "DCT" t = datetime.datetime.now() + datetime.timedelta(minutes = 20) flight.departureTime = datetime.datetime(t.year, t.month, t.day, t.hour, t.minute) t = flight.departureTime + datetime.timedelta(minutes = 30) flight.arrivalTime = datetime.datetime(t.year, t.month, t.day, t.hour, t.minute) return flight def __init__(self, id = None): """Construct a booked flight with the given ID.""" self.id = id @property def status(self): """Get the status of the flight. For web-based flights this is always STATUS_BOOKED.""" return BookedFlight.STATUS_BOOKED def readFromWeb(self, f): """Read the data of the flight from the web via the given file object.""" self.callsign = readline(f) date = readline(f) print("web.BookedFlight.readFromWeb: date:", date) if date=="0000-00-00": date = "0001-01-01" self.departureICAO = readline(f) self.arrivalICAO = readline(f) self._readAircraftType(f) self.tailNumber = readline(f) self.numPassengers = int(readline(f)) self.numCrew = int(readline(f)) self.bagWeight = int(readline(f)) self.cargoWeight = int(readline(f)) self.mailWeight = int(readline(f)) self.route = readline(f) departureTime = readline(f) self.departureTime = BookedFlight.getDateTime(date, departureTime) arrivalTime = readline(f) self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime) if self.arrivalTime=0: line = line[:hashIndex] if line: equalIndex = line.find("=") lineOK = equalIndex>0 if lineOK: key = line[:equalIndex].strip() value = line[equalIndex+1:].strip().replace("\:", ":") lineOK = key and value if lineOK: if key=="callsign": self.callsign = value elif key=="date": date = value elif key=="dep_airport": self.departureICAO = value elif key=="dest_airport": self.arrivalICAO = value elif key=="planecode": self.aircraftType = \ self._decodeAircraftType(value) elif key=="planetype": self.aircraftTypeName = value elif key=="tail_nr": self.tailNumber = value elif key=="passenger": self.numPassengers = int(value) elif key=="crew": self.numCrew = int(value) elif key=="bag": self.bagWeight = int(value) elif key=="cargo": self.cargoWeight = int(value) elif key=="mail": self.mailWeight = int(value) elif key=="flight_route": self.route = value elif key=="departure_time": departureTime = value elif key=="arrival_time": arrivalTime = value elif key=="foglalas_id": self.id = None if value=="0" else value else: lineOK = False if not lineOK: print("web.BookedFlight.readFromFile: line %d is invalid" % \ (lineNumber,)) line = f.readline() if date is not None: if departureTime is not None: self.departureTime = BookedFlight.getDateTime(date, departureTime) if arrivalTime is not None: self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime) d = dir(self) for attribute in ["callsign", "departureICAO", "arrivalICAO", "aircraftType", "tailNumber", "numPassengers", "numCrew", "bagWeight", "cargoWeight", "mailWeight", "route", "departureTime", "arrivalTime"]: if attribute not in d: raise Exception("Attribute %s could not be read" % (attribute,)) if "aircraftTypeName" not in d: self.aircraftTypeName = \ BookedFlight.TYPE2TYPECODE[self.aircraftType] def setupFromPIREPData(self, pirepData): """Setup the booked flight from the given PIREP data.""" bookedFlightData = pirepData["bookedFlight"] self.callsign = bookedFlightData["callsign"] date = bookedFlightData["date"] departureTime = bookedFlightData["departureTime"] self.departureTime = BookedFlight.getDateTime(date, departureTime) arrivalTime = bookedFlightData["arrivalTime"] self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime) if self.arrivalTime2 else None self._setStatus(status) gateNumber = words[1] if len(words)>1 else "" self.gateNumber = gateNumber if gateNumber else None except: print("Plane string is invalid: '" + s + "'", file=sys.stderr) self.tailNumber = None #------------------------------------------------------------------------------ class Fleet(rpccommon.Fleet): """Information about the whole fleet.""" def __init__(self, f): """Construct the fleet information by reading the given file object.""" super(Fleet, self).__init__() while True: line = readline(f) if not line or line == "#END": break plane = Plane(line) self._addPlane(plane) #------------------------------------------------------------------------------ class NOTAM(object): """A NOTAM for an airport.""" def __init__(self, ident, basic, begin, notice, end = None, permanent = False, repeatCycle = None): """Construct the NOTAM.""" self.ident = ident self.basic = basic self.begin = begin self.notice = notice self.end = end self.permanent = permanent self.repeatCycle = repeatCycle def __repr__(self): """Get the representation of the NOTAM.""" s = "=6: if words[5] in ["PERM", "UFN"]: permanent = True else: end = datetime.datetime.strptime(words[5], "%y%m%d%H%M") else: permanent = True repeatCycle = None noticeStartIndex = 3 if lines[3].startswith("D)"): repeatCycle = lines[3][2:].strip() noticeStartIndex = 4 notice = "" for index in range(noticeStartIndex, len(lines)): line = lines[index][2:] if index==noticeStartIndex else lines[index] line = line.strip() if line.lower().startswith("created:") or \ line.lower().startswith("source:"): break if notice: notice += " " notice += line return NOTAM(ident, basic, begin, notice, end = end, permanent = permanent, repeatCycle = repeatCycle) def _parseCurrentNOTAM2(self): """Parse the current NOTAM with a second, more flexible method.""" self._currentNOTAM = self._currentNOTAM.replace("\\n", "\n") lines = self._currentNOTAM.splitlines() if len(lines)==1: lines = lines[0].splitlines() lines = [line.strip() for line in lines] if not lines: return None ident = lines[0].split()[0] lines = lines[1:] for i in range(0, 2): l = lines[-1].lower() if l.startswith("created:") or l.startswith("source:"): lines = lines[:-1] lines = [line.strip() for line in lines] contents = " ".join(lines).split() items = {} for i in ["Q)", "A)", "B)", "C)", "D)", "E)"]: items[i] = "" currentItem = None for word in contents: if word in items: currentItem = word elif currentItem in items: s = items[currentItem] if s: s+= " " s += word items[currentItem] = s if not items["Q)"] or not items["A)"] or not items["B)"] or \ not items["E)"]: return None def parseTime(item): item = re.sub("([0-9]+).*", "\\1", item) try: return datetime.datetime.strptime(item, "%y%m%d%H%M") except ValueError: return datetime.datetime.strptime(item, "%Y%m%d%H%M") basic = items["Q)"] begin = parseTime(items["B)"]) end = None permanent = False if items["C)"]: endItem = items["C)"] if endItem in ["PERM", "UFN"]: permanent = True else: end = parseTime(items["C)"]) else: permanent = True repeatCycle = None if items["D)"]: repeatCycle = items["D)"] notice = items["E)"] return NOTAM(ident, basic, begin, notice, end = end, permanent = permanent, repeatCycle = repeatCycle) #------------------------------------------------------------------------------ class Result(object): """A result object. An instance of this filled with the appropriate data is passed to the callback function on each request.""" def __repr__(self): """Get a representation of the result.""" s = "" return s #------------------------------------------------------------------------------ class Request(object): """Base class for requests. It handles any exceptions and the calling of the callback. If an exception occurs during processing, the callback is called with the two parameters: a boolean value of False, and the exception object. If no exception occurs, the callback is called with True and the return value of the run() function. If the callback function throws an exception, that is caught and logged to the debug log.""" def __init__(self, callback): """Construct the request.""" self._callback = callback def perform(self): """Perform the request. The object's run() function is called. If it throws an exception, the callback is called with False, and the exception. Otherwise the callback is called with True and the return value of the run() function. Any exceptions thrown by the callback are caught and reported.""" try: result = self.run() returned = True except Exception as e: traceback.print_exc() result = e returned = False try: self._callback(returned, result) except Exception as e: print("web.Handler.Request.perform: callback throwed an exception: " + util.utf2unicode(str(e)), file=sys.stderr) #traceback.print_exc() #------------------------------------------------------------------------------ class RPCRequest(Request): """Common base class for RPC requests. It stores the RPC client received from the handler.""" def __init__(self, client, callback): """Construct the request.""" super(RPCRequest, self).__init__(callback) self._client = client #------------------------------------------------------------------------------ class Register(RPCRequest): """A registration request.""" def __init__(self, client, callback, registrationData): """Construct the request.""" super(Register, self).__init__(client, callback) self._registrationData = registrationData def run(self): """Perform the registration.""" registrationData = self._registrationData (resultCode, pilotID) = self._client.register(registrationData) result = Result() result.registered = resultCode==rpc.Client.RESULT_OK if result.registered: result.pilotID = pilotID self._client.setCredentials(pilotID, registrationData.password) LoginRPC.setupLoginResult(result, self._client, pilotID, registrationData.password) result.invalidData = \ resultCode==rpc.Client.RESULT_INVALID_DATA result.emailAlreadyRegistered = \ resultCode==rpc.Client.RESULT_EMAIL_ALREADY_REGISTERED return result #------------------------------------------------------------------------------ class Login(Request): """A login request.""" iso88592decoder = codecs.getdecoder("iso-8859-2") def __init__(self, callback, pilotID, password): """Construct the login request with the given pilot ID and password.""" super(Login, self).__init__(callback) self._pilotID = pilotID self._password = password def run(self): """Perform the login request.""" md5 = hashlib.md5() md5.update(self._pilotID) pilotID = md5.hexdigest() md5 = hashlib.md5() md5.update(self._password) password = md5.hexdigest() url = MAVA_BASE_URL + "/leker2.php?pid=%s&psw=%s" % (pilotID, password) result = Result() f = urllib.request.urlopen(url, timeout = 10.0) status = readline(f) result.loggedIn = status == ".OK." if result.loggedIn: result.pilotID = self._pilotID result.password = self._password result.rank = "FO" result.flights = [] result.pilotName = self.iso88592decoder(readline(f))[0] result.exams = readline(f) while True: line = readline(f) if not line or line == "#ENDPIREP": break flight = BookedFlight(line) flight.readFromWeb(f) result.flights.append(flight) result.flights.sort(key = lambda flight: flight.departureTime) f.close() return result #------------------------------------------------------------------------------ class LoginRPC(RPCRequest): """An RPC-based login request.""" @staticmethod def setupLoginResult(result, client, pilotID, password): """Setup the login result with the given client, pilot ID and password.""" loginResult = client.login() result.loggedIn = loginResult is not None if result.loggedIn: result.pilotID = pilotID result.pilotName = loginResult[0] result.rank = loginResult[1] result.types = loginResult[2] result.password = password flights = client.getFlights() result.flights = flights[0] result.reportedFlights = flights[1] result.rejectedFlights = flights[2] if result.rank=="STU": reply = client.getEntryExamStatus() result.entryExamPassed = reply[0] result.entryExamLink = reply[1] result.checkFlightStatus = reply[2] if reply[3]: result.rank = "FO" def __init__(self, client, callback, pilotID, password): """Construct the login request with the given pilot ID and password.""" super(LoginRPC, self).__init__(client, callback) self._pilotID = pilotID self._password = password def run(self): """Perform the login request.""" result = Result() self._client.setCredentials(self._pilotID, self._password) LoginRPC.setupLoginResult(result, self._client, self._pilotID, self._password) return result #------------------------------------------------------------------------------ class GetEntryExamStatus(RPCRequest): """A request to get the entry exam status.""" def __init__(self, client, callback): """Construct the request.""" super(GetEntryExamStatus, self).__init__(client, callback) def run(self): """Perform the query.""" result = Result() reply = self._client.getEntryExamStatus() result.entryExamPassed = reply[0] result.entryExamLink = reply[1] result.checkFlightStatus = reply[2] result.madeFO = reply[3] return result #------------------------------------------------------------------------------ class GetFleet(Request): """Request to get the fleet from the website.""" def __init__(self, callback): """Construct the fleet request.""" super(GetFleet, self).__init__(callback) def run(self): """Perform the login request.""" url = MAVA_BASE_URL + "/onlinegates_get.php" f = urllib.request.urlopen(url, timeout = 10.0) result = Result() result.fleet = Fleet(f) f.close() return result #------------------------------------------------------------------------------ class GetFleetRPC(RPCRequest): """Request to get the fleet from the website using RPC.""" def __init__(self, client, callback): """Construct the request with the given client and callback function.""" super(GetFleetRPC, self).__init__(client, callback) def run(self): """Perform the login request.""" result = Result() result.fleet = self._client.getFleet() return result #------------------------------------------------------------------------------ class UpdatePlane(Request): """Update the status of one of the planes in the fleet.""" def __init__(self, callback, tailNumber, status, gateNumber = None): """Construct the request.""" super(UpdatePlane, self).__init__(callback) self._tailNumber = tailNumber self._status = status self._gateNumber = gateNumber def run(self): """Perform the plane update.""" url = MAVA_BASE_URL + "/onlinegates_set.php" status = Plane.status2str(self._status) gateNumber = self._gateNumber if self._gateNumber else "" data = urllib.parse.urlencode([("lajstrom", self._tailNumber), ("status", status), ("kapu", gateNumber)]) f = urllib.request.urlopen(url, data, timeout = 10.0) line = readline(f) result = Result() result.success = line == "OK" return result #------------------------------------------------------------------------------ class UpdatePlaneRPC(RPCRequest): """RPC request to update the status and the position of a plane in the fleet.""" def __init__(self, client, callback, tailNumber, status, gateNumber = None): """Construct the request.""" super(UpdatePlaneRPC, self).__init__(client, callback) self._tailNumber = tailNumber self._status = status self._gateNumber = gateNumber def run(self): """Perform the plane update.""" self._client.updatePlane(self._tailNumber, self._status, self._gateNumber) # Otherwise an exception is thrown result = Result() result.success = True return result #------------------------------------------------------------------------------ class GetNOTAMs(Request): """Get the NOTAMs from EURoutePro and select the ones we are interested in.""" def __init__(self, callback, departureICAO, arrivalICAO): """Construct the request for the given airports.""" super(GetNOTAMs, self).__init__(callback) self._departureICAO = departureICAO self._arrivalICAO = arrivalICAO def run(self): """Perform the retrieval of the NOTAMs.""" departureNOTAMs = self.getPilotsWebNOTAMs(self._departureICAO) arrivalNOTAMs = self.getPilotsWebNOTAMs(self._arrivalICAO) icaos = [] if not departureNOTAMs: icaos.append(self._departureICAO) if not arrivalNOTAMs: icaos.append(self._arrivalICAO) if icaos: xmlParser = xml.sax.make_parser() notamHandler = NOTAMHandler(icaos) xmlParser.setContentHandler(notamHandler) url = "http://notams.euroutepro.com/notams.xml" f = urllib.request.urlopen(url, timeout = 10.0) try: xmlParser.parse(f) finally: f.close() for icao in icaos: if icao==self._departureICAO: departureNOTAMs = notamHandler.get(icao) else: arrivalNOTAMs = notamHandler.get(icao) result = Result() result.departureNOTAMs = departureNOTAMs result.arrivalNOTAMs = arrivalNOTAMs return result def getPilotsWebNOTAMs(self, icao): """Try to get the NOTAMs from FAA's PilotsWeb site for the given ICAO code. Returns a list of PilotsWEBNOTAM objects, or None in case of an error.""" try: parser = PilotsWebNOTAMsParser() url = "https://pilotweb.nas.faa.gov/PilotWeb/notamRetrievalByICAOAction.do?method=displayByICAOs&formatType=ICAO&retrieveLocId=%s&reportType=RAW&actionType=notamRetrievalByICAOs" % \ (icao.upper(),) f = urllib.request.urlopen(url, timeout = 10.0) try: data = f.read(16384) while data: parser.feed(str(data)) data = f.read(16384) finally: f.close() return parser.getNOTAMs() except Exception as e: traceback.print_exc() print("mlx.web.GetNOTAMs.getPilotsWebNOTAMs: failed to get NOTAMs for '%s': %s" % \ (icao, str(e))) return None #------------------------------------------------------------------------------ class GetMETARs(Request): """Get the METARs from the NOAA website for certain airport ICAOs.""" def __init__(self, callback, airports): """Construct the request for the given airports.""" super(GetMETARs, self).__init__(callback) self._airports = airports def run(self): """Perform the retrieval opf the METARs.""" url = "http://www.aviationweather.gov/adds/dataserver_current/httpparam?" data = urllib.parse.urlencode([ ("dataSource" , "metars"), ("requestType", "retrieve"), ("format", "csv"), ("stationString", " ".join(self._airports)), ("hoursBeforeNow", "24"), ("mostRecentForEachStation", "constraint")]) url += data f = urllib.request.urlopen(url, timeout = 10.0) try: result = Result() result.metars = {} for line in f.readlines(): line = str(line, "iso-8859-1") if len(line)>5 and line[4]==' ': icao = line[0:4] if icao in self._airports: result.metars[icao] = line.strip().split(",")[0] finally: f.close() return result #------------------------------------------------------------------------------ class SendPIREP(Request): """A request to send a PIREP to the MAVA website.""" _latin2Encoder = codecs.getencoder("iso-8859-2") def __init__(self, callback, pirep): """Construct the sending of the PIREP.""" super(SendPIREP, self).__init__(callback) self._pirep = pirep def run(self): """Perform the sending of the PIREP.""" url = MAVA_BASE_URL + "/malevacars.php" pirep = self._pirep data = {} data["acarsdata"] = SendPIREP._latin2Encoder(pirep.getACARSText())[0] bookedFlight = pirep.bookedFlight data["foglalas_id"] = bookedFlight.id data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d") data["fltnum"] = bookedFlight.callsign data["depap"] = bookedFlight.departureICAO data["arrap"] = bookedFlight.arrivalICAO data["pass"] = str(pirep.numPassengers) data["crew"] = str(pirep.numCrew) data["cargo"] = str(pirep.cargoWeight) data["bag"] = str(pirep.bagWeight) data["mail"] = str(pirep.mailWeight) data["flttype"] = pirep.flightTypeText data["onoff"] = "1" if pirep.online else "0" data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart) data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd) data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd - pirep.blockTimeStart) data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart) data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd) data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd - pirep.flightTimeStart) data["timecomm"] = pirep.getTimeComment() data["fuel"] = "%.2f" % (pirep.fuelUsed,) data["dep_rwy"] = pirep.departureRunway data["arr_rwy"] = pirep.arrivalRunway data["wea_dep"] = pirep.departureMETAR data["wea_arr"] = pirep.arrivalMETAR data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,) if pirep.filedCruiseAltitude!=pirep.cruiseAltitude: data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,) else: data["mod_alt"] = "" data["sid"] = pirep.sid data["navroute"] = pirep.route data["star"] = pirep.getSTAR() data["aprtype"] = pirep.approachType data["diff"] = "2" data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0] data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0] data["kritika"] = pirep.getRatingText() data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),) data["distance"] = "%.3f" % (pirep.flownDistance,) data["insdate"] = datetime.date.today().strftime("%Y-%m-%d") postData = urllib.parse.urlencode(data) f = urllib.request.urlopen(url, postData, timeout = 10.0) try: result = Result() line = f.readline().strip() print("PIREP result from website:", line) result.success = line=="OK" result.alreadyFlown = line=="MARVOLT" result.notAvailable = line=="NOMORE" finally: f.close() return result #------------------------------------------------------------------------------ class SendPIREPRPC(RPCRequest): """A request to send a PIREP to the MAVA website via the RPC interface.""" def __init__(self, client, callback, pirep, update): """Construct the sending of the PIREP.""" super(SendPIREPRPC, self).__init__(client, callback) self._pirep = pirep self._update = update def run(self): """Perform the sending of the PIREP.""" pirep = self._pirep resultCode = self._client.addPIREP(pirep.bookedFlight.id, pirep, self._update) result = Result() result.success = resultCode==rpc.Client.RESULT_OK result.alreadyFlown = resultCode==rpc.Client.RESULT_FLIGHT_ALREADY_REPORTED result.notAvailable = resultCode==rpc.Client.RESULT_FLIGHT_NOT_EXISTS return result #------------------------------------------------------------------------------ class SendACARS(Request): """A request to send an ACARS to the MAVA website.""" _latin2Encoder = codecs.getencoder("iso-8859-2") def __init__(self, callback, acars): """Construct the request for the given PIREP.""" super(SendACARS, self).__init__(callback) self._acars = acars def run(self): """Perform the sending of the ACARS.""" print("Sending the online ACARS") url = MAVA_BASE_URL + "/acars2/acarsonline.php" acars = self._acars bookedFlight = acars.bookedFlight data = {} data["pid"] = acars.pid data["pilot"] = SendACARS._latin2Encoder(acars.pilotName)[0] data["pass"] = str(bookedFlight.numPassengers) data["callsign"] = bookedFlight.callsign data["airplane"] = bookedFlight.aircraftTypeName data["from"] = bookedFlight.departureICAO data["to"] = bookedFlight.arrivalICAO data["lajstrom"] = bookedFlight.tailNumber data["block_time"] = acars.getBlockTimeText() data["longitude"] = str(acars.state.longitude) data["latitude"] = str(acars.state.latitude) data["altitude"] = str(acars.state.altitude) data["speed"] = str(acars.state.groundSpeed) data["event"] = acars.getEventText() f = urllib.request.urlopen(url, urllib.parse.urlencode(data), timeout = 10.0) try: result = Result() finally: f.close() return result #------------------------------------------------------------------------------ class SendACARSRPC(RPCRequest): """A request to send an ACARS to the MAVA website via JSON-RPC.""" def __init__(self, client, callback, acars): """Construct the request for the given PIREP.""" super(SendACARSRPC, self).__init__(client, callback) self._acars = acars def run(self): """Perform the sending of the ACARS.""" print("Sending the online ACARS via JSON-RPC") self._client.updateOnlineACARS(self._acars) return Result() #------------------------------------------------------------------------------ class SendBugReport(Request): """A request to send a bug report to the project homepage.""" _latin2Encoder = codecs.getencoder("iso-8859-2") def __init__(self, callback, summary, description, email): """Construct the request for the given bug report.""" super(SendBugReport, self).__init__(callback) self._summary = summary self._description = description self._email = email def run(self): """Perform the sending of the bug report.""" serverProxy = xmlrpc.client.ServerProxy("http://mlx.varadiistvan.hu/rpc") result = Result() result.success = False attributes = {} if self._email: attributes["reporter"] = self._email result.ticketID = serverProxy.ticket.create(self._summary, self._description, attributes, True) print("Created ticket with ID:", result.ticketID) result.success = True return result #------------------------------------------------------------------------------ class SetCheckFlightPassed(RPCRequest): """A request to mark the user as one having passed the check flight.""" def __init__(self, client, callback, aircraftType): """Construct the request for the given type.""" super(SetCheckFlightPassed, self).__init__(client, callback) self._aircraftType = aircraftType def run(self): """Perform the update.""" aircraftType = BookedFlight.TYPE2TYPECODE[self._aircraftType] self._client.setCheckFlightPassed(aircraftType) return Result() #------------------------------------------------------------------------------ class GetPIREP(RPCRequest): """A request to retrieve the PIREP of a certain flight.""" def __init__(self, client, callback, flightID): """Construct the request.""" super(GetPIREP, self).__init__(client, callback) self._flightID = flightID def run(self): """Perform the update.""" result = Result() pirepData = self._client.getPIREP(self._flightID) print("pirepData:", pirepData) bookedFlight = BookedFlight(self._flightID) bookedFlight.setupFromPIREPData(pirepData) result.pirep = PIREP(None) result.pirep.setupFromPIREPData(pirepData, bookedFlight) return result #------------------------------------------------------------------------------ class ReflyFlights(RPCRequest): """A request to mark certain flights for reflying.""" def __init__(self, client, callback, flightIDs): """Construct the request.""" super(ReflyFlights, self).__init__(client, callback) self._flightIDs = flightIDs def run(self): """Perform the update.""" self._client.reflyFlights(self._flightIDs) return Result() #------------------------------------------------------------------------------ class DeleteFlights(RPCRequest): """A request to delete certain flights.""" def __init__(self, client, callback, flightIDs): """Construct the request.""" super(DeleteFlights, self).__init__(client, callback) self._flightIDs = flightIDs def run(self): """Perform the update.""" self._client.deleteFlights(self._flightIDs) return Result() #------------------------------------------------------------------------------ class GetAcceptedFlights(RPCRequest): """Request to get the accepted flights.""" def __init__(self, client, callback): """Construct the request with the given client and callback function.""" super(GetAcceptedFlights, self).__init__(client, callback) def run(self): """Perform the login request.""" result = Result() result.flights = self._client.getAcceptedFlights() return result #------------------------------------------------------------------------------ class GetTimetable(RPCRequest): """Request to get the timetable.""" def __init__(self, client, callback, date, types): """Construct the request with the given client and callback function.""" super(GetTimetable, self).__init__(client, callback) self._date = date self._types = types def run(self): """Perform the login request.""" result = Result() result.flightPairs = self._client.getTimetable(self._date, self._types) return result #------------------------------------------------------------------------------ class BookFlights(RPCRequest): """Request to book flights.""" def __init__(self, client, callback, flightIDs, date, tailNumber): """Construct the request with the given client and callback function.""" super(BookFlights, self).__init__(client, callback) self._flightIDs = flightIDs self._date = date self._tailNumber = tailNumber def run(self): """Perform the login request.""" result = Result() result.bookedFlights = self._client.bookFlights(self._flightIDs, self._date, self._tailNumber) return result #------------------------------------------------------------------------------ class Handler(threading.Thread): """The handler for the web services. It can process one request at a time. The results are passed to a callback function.""" def __init__(self, config, getCredentialsFn): """Construct the handler.""" super(Handler, self).__init__() self._requests = [] self._requestCondition = threading.Condition() self.daemon = True self._config = config self._rpcClient = rpc.Client(getCredentialsFn) if config.rememberPassword: self._rpcClient.setCredentials(config.pilotID, config.password) def register(self, callback, registrationData): """Enqueue a registration request.""" self._addRequest(Register(self._rpcClient, callback, registrationData)) def login(self, callback, pilotID, password): """Enqueue a login request.""" request = \ LoginRPC(self._rpcClient, callback, pilotID, password) \ if self._config.useRPC else Login(callback, pilotID, password) self._addRequest(request) def getEntryExamStatus(self, callback): """Get the entry exam status.""" self._addRequest(GetEntryExamStatus(self._rpcClient, callback)) def getFleet(self, callback): """Enqueue a fleet retrieval request.""" request = \ GetFleetRPC(self._rpcClient, callback,) if self._config.useRPC \ else GetFleet(callback) self._addRequest(request) def updatePlane(self, callback, tailNumber, status, gateNumber = None): """Update the status of the given plane.""" request = \ UpdatePlaneRPC(self._rpcClient, callback, tailNumber, status, gateNumber) \ if self._config.useRPC \ else UpdatePlane(callback, tailNumber, status, gateNumber) self._addRequest(request) def getNOTAMs(self, callback, departureICAO, arrivalICAO): """Get the NOTAMs for the given two airports.""" self._addRequest(GetNOTAMs(callback, departureICAO, arrivalICAO)) def getMETARs(self, callback, airports): """Get the METARs for the given airports.""" self._addRequest(GetMETARs(callback, airports)) def sendPIREP(self, callback, pirep, update = False): """Send the given PIREP.""" request = \ SendPIREPRPC(self._rpcClient, callback, pirep, update) \ if self._config.useRPC else SendPIREP(callback, pirep) self._addRequest(request) def sendACARS(self, callback, acars): """Send the given ACARS""" request = \ SendACARSRPC(self._rpcClient, callback, acars) if self._config.useRPC \ else SendACARS(callback, acars) self._addRequest(request) def sendBugReport(self, callback, summary, description, email): """Send a bug report with the given data.""" self._addRequest(SendBugReport(callback, summary, description, email)) def setCheckFlightPassed(self, callback, aircraftType): """Mark the check flight as passed.""" self._addRequest(SetCheckFlightPassed(self._rpcClient, callback, aircraftType)) def getPIREP(self, callback, flightID): """Query the PIREP for the given flight.""" self._addRequest(GetPIREP(self._rpcClient, callback, flightID)) def reflyFlights(self, callback, flightIDs): """Mark the flights with the given IDs for reflying.""" self._addRequest(ReflyFlights(self._rpcClient, callback, flightIDs)) def deleteFlights(self, callback, flightIDs): """Delete the flights with the given IDs.""" self._addRequest(DeleteFlights(self._rpcClient, callback, flightIDs)) def getAcceptedFlights(self, callback): """Enqueue a request to get the accepted flights.""" self._addRequest(GetAcceptedFlights(self._rpcClient, callback)) def getTimetable(self, callback, date, types): """Enqueue a request to get the timetable.""" self._addRequest(GetTimetable(self._rpcClient, callback, date, types)) def bookFlights(self, callback, flightIDs, date, tailNumber): """Enqueue a request to book some flights.""" self._addRequest(BookFlights(self._rpcClient, callback, flightIDs, date, tailNumber)) def run(self): """Process the requests.""" while True: with self._requestCondition: while not self._requests: self._requestCondition.wait() request = self._requests[0] del self._requests[0] request.perform() def _addRequest(self, request): """Add the given request to the queue.""" with self._requestCondition: self._requests.append(request) self._requestCondition.notify() #------------------------------------------------------------------------------ if __name__ == "__main__": import time def callback(returned, result): print(returned, str(result)) handler = Handler() handler.start() #handler.login(callback, "P096", "V5fwj") #handler.getFleet(callback) # Plane: HA-LEG home (gate 67) #handler.updatePlane(callback, "HA-LQC", const.PLANE_AWAY, "72") #time.sleep(3) #handler.getFleet(callback) #time.sleep(3) #handler.getNOTAMs(callback, "LHBP", "EPWA") #handler.getMETARs(callback, ["LHBP", "EPWA"]) #time.sleep(5) handler.updatePlane(callback, "HA-LON", const.PLANE_AWAY, "") time.sleep(3) #------------------------------------------------------------------------------