218 lines
7.9 KiB
Python
218 lines
7.9 KiB
Python
#!/usr/bin/env python
|
|
|
|
import json
|
|
import os
|
|
from subprocess import Popen, PIPE
|
|
|
|
from flask import Flask, Response, request
|
|
from flask_cors import CORS, cross_origin
|
|
from json import JSONEncoder
|
|
|
|
from aman.AMAN import AMAN
|
|
from aman.config.AirportSequencing import AirportSequencing
|
|
from aman.config.RunwaySequencing import RunwaySequencing
|
|
|
|
class InboundEncoder(JSONEncoder):
|
|
def default(self, o):
|
|
if None == o.PlannedArrivalTime or None == o.EnrouteArrivalTime or None == o.PlannedRunway:
|
|
return {}
|
|
|
|
# configure the PTA
|
|
pta = str(o.PlannedArrivalTime)
|
|
delimiter = pta.find('.')
|
|
if -1 == delimiter:
|
|
delimiter = pta.find('+')
|
|
|
|
# calculate the delta time
|
|
delta = int((o.PlannedArrivalTime - o.EnrouteArrivalTime).total_seconds() / 60.0);
|
|
|
|
return {
|
|
'callsign' : o.Callsign,
|
|
'fixed' : o.FixedSequence,
|
|
'runway' : o.PlannedRunway.Name,
|
|
'pta' : pta[0:delimiter],
|
|
'delay' : delta,
|
|
'wtc' : o.WTC,
|
|
'iaf' : o.Report.initialApproachFix,
|
|
'expectedrunway' : o.ExpectedRunway,
|
|
'assignmentmode' : o.AssignmentMode
|
|
}
|
|
|
|
class RunwaySequencingEncoder(JSONEncoder):
|
|
def default(self, o):
|
|
return { 'runway' : o.Runway.Name, 'spacing' : o.Spacing }
|
|
|
|
# initialize the environment variables
|
|
if 'AMAN_PATH' not in os.environ:
|
|
os.environ['AMAN_PATH'] = 'C:\\Repositories\VATSIM\\AMAN\\aman-sys\\aman'
|
|
if 'AMAN_CONFIG_PATH' not in os.environ:
|
|
os.environ['AMAN_CONFIG_PATH'] = 'C:\\Repositories\\VATSIM\\AMAN\\config'
|
|
|
|
# initialize the AMAN and the interface version
|
|
aman = AMAN()
|
|
version = '0.0.0'
|
|
with open(os.path.join(os.environ['AMAN_PATH'], 'VERSION')) as file:
|
|
version = file.readline()
|
|
|
|
# initialize the web services
|
|
app = Flask('AMAN')
|
|
cors = CORS(app)
|
|
app.config['CORS_HEADERS'] = 'Content-Type'
|
|
if __name__ == '__main__':
|
|
app.run()
|
|
|
|
@app.route('/aman/airports')
|
|
@cross_origin()
|
|
def airports():
|
|
# get the airports
|
|
retval = []
|
|
for airport in aman.Workers:
|
|
retval.append(airport.Icao)
|
|
|
|
data = json.dumps({ 'version' : version, 'airports' : retval }, ensure_ascii=True)
|
|
return Response(data, status=200, mimetype='application/json')
|
|
|
|
@app.route('/aman/admin/newuser')
|
|
def newUser():
|
|
toolpath = os.path.join(os.path.join(os.environ['AMAN_PATH'], 'tools'), 'KeyPairCreator.py')
|
|
serverKeypath = os.path.join(os.path.join(os.path.join(AMAN.findConfigPath(), 'keys'), 'server'), 'server.key')
|
|
clientKeypath = os.path.join(os.path.join(AMAN.findConfigPath(), 'keys'), 'clients')
|
|
|
|
cmd = ['python', toolpath, '--directory=' + clientKeypath, '--publickey=' + serverKeypath]
|
|
|
|
child = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
|
stdout, _ = child.communicate()
|
|
if 0 != child.returncode:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
keys = stdout.splitlines()
|
|
server = keys[0].decode('ascii')
|
|
public = keys[1].decode('ascii')
|
|
private = keys[2].decode('ascii')
|
|
|
|
dictionary = {
|
|
'server' : server,
|
|
'public' : public,
|
|
'private' : private,
|
|
}
|
|
data = json.dumps(dictionary, ensure_ascii=True)
|
|
return Response(data, status=200, mimetype='application/json')
|
|
|
|
@app.route('/aman/configuration/<icao>')
|
|
@cross_origin()
|
|
def configuration(icao):
|
|
airport = aman.findAirport(icao.upper())
|
|
if None == airport:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
# get the current runway configuration
|
|
config = airport.SequencingConfiguration
|
|
dependencies = []
|
|
for dependency in config.RunwayDependencies:
|
|
rwy0 = config.runway(dependency[0])
|
|
rwy1 = config.runway(dependency[1])
|
|
cand1 = [ rwy0.Name, rwy1.Name ]
|
|
cand2 = [ rwy1.Name, rwy0.Name ]
|
|
found = False
|
|
|
|
for dep in dependencies:
|
|
if cand1 == dep or cand2 == dep:
|
|
found = True
|
|
break
|
|
|
|
if False == found:
|
|
dependencies.append(cand1)
|
|
|
|
runways = airport.Configuration.GngData.Runways[airport.Icao];
|
|
availableRunways = [];
|
|
for runway in runways:
|
|
availableRunways.append(runway.Name);
|
|
|
|
dictionary = {
|
|
'airport' : airport.Icao,
|
|
'useShallShouldMay' : config.UseShallShouldMay,
|
|
'availableRunways' : availableRunways,
|
|
'activeRunways' : config.ActiveArrivalRunways,
|
|
'dependentRunways' : dependencies,
|
|
'iafColorization' : airport.Configuration.IafColorization
|
|
}
|
|
data = json.dumps(dictionary, ensure_ascii=True, cls=RunwaySequencingEncoder)
|
|
return Response(data, status=200, mimetype='application/json')
|
|
|
|
@app.route('/aman/sequence/<icao>')
|
|
@cross_origin()
|
|
def sequence(icao):
|
|
airport = aman.findAirport(icao.upper())
|
|
if None == airport:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
# convert the timestamp
|
|
stamp = str(airport.SequencingConfiguration.LastUpdateTimestamp)
|
|
delimiter = stamp.find('.')
|
|
if -1 == delimiter:
|
|
delimiter = stamp.find('+')
|
|
|
|
dictionary = {
|
|
'airport': airport.Icao,
|
|
'lastConfigurationUpdate': stamp[0:delimiter],
|
|
'sequence': airport.inboundSequence()
|
|
}
|
|
data = json.dumps(dictionary, ensure_ascii=True, cls=InboundEncoder)
|
|
return Response(data, status=200, mimetype='application/json')
|
|
|
|
@app.route('/aman/configure', methods=['POST'])
|
|
@cross_origin()
|
|
def configure():
|
|
data = request.get_json()
|
|
|
|
# validate that the airport exists
|
|
if 'airport' not in data:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
airport = aman.findAirport(data['airport'].upper())
|
|
if None == airport:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
# check that all top-level information are available
|
|
if 'useShallShouldMay' not in data or 'activeRunways' not in data or 'dependentRunways' not in data:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
if False == isinstance(data['useShallShouldMay'], bool) or 0 == len(data['activeRunways']):
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
# create the toplevel information
|
|
config = AirportSequencing(airport.Icao)
|
|
config.Airport = data['airport'].upper()
|
|
config.UseShallShouldMay = data['useShallShouldMay']
|
|
|
|
# parse the active runways
|
|
for activeRunway in data['activeRunways']:
|
|
if 'runway' not in activeRunway or 'spacing' not in activeRunway:
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
if False == isinstance(activeRunway['runway'], str) or False == isinstance(activeRunway['spacing'], int):
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
gngRunway = None
|
|
for runway in airport.Configuration.GngData.Runways[airport.Icao]:
|
|
if runway.Name == activeRunway['runway']:
|
|
gngRunway = runway
|
|
break
|
|
|
|
# could not find the runway
|
|
if None == gngRunway:
|
|
return None
|
|
|
|
runway = RunwaySequencing(gngRunway)
|
|
runway.Spacing = activeRunway['spacing']
|
|
config.activateRunway(runway)
|
|
|
|
# parse the dependent runways
|
|
for dependency in data['dependentRunways']:
|
|
if 2 != len(dependency) or False == isinstance(dependency[0], str) or False == isinstance(dependency[1], str):
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
if False == config.addDependency(dependency[0], dependency[1]):
|
|
return Response('{}', status=404, mimetype='application/json')
|
|
|
|
airport.Configuration.assignmentUpdate(config)
|
|
airport.configure(config)
|
|
|
|
return Response('{}', status=200, mimetype='application/json')
|