199 行
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			199 行
		
	
	
		
			7.3 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):
 | 
						|
        pta = str(o.PlannedArrivalTime)
 | 
						|
        delimiter = pta.find('.')
 | 
						|
        if -1 == delimiter:
 | 
						|
            delimiter = pta.find('+')
 | 
						|
        delta = int((o.PlannedArrivalTime - o.InitialArrivalTime).total_seconds() / 60.0);
 | 
						|
        return { 'callsign' : o.Callsign, 'fixed' : o.FixedSequence, 'runway' : o.PlannedRunway.Name, 'pta' : pta[0:delimiter], 'delay' : delta }
 | 
						|
 | 
						|
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')
 | 
						|
 | 
						|
    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
 | 
						|
    }
 | 
						|
    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')
 |