app.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import uuid
  2. import threading
  3. import time
  4. import queue
  5. import os
  6. import zipfile
  7. import shutil
  8. from flask import Flask
  9. from flask import render_template
  10. from flask import request
  11. from flask import json, jsonify
  12. from MAVProxy.modules.mavproxy_map import srtm
  13. from terrain_gen import makeTerrain
  14. # The output folder for all zipped terrain requests
  15. app = Flask(__name__,static_url_path='/terrain', static_folder='outputTer',)
  16. def clamp(n, smallest, largest):
  17. return max(smallest, min(n, largest))
  18. class TerGenThread(threading.Thread):
  19. # This is the terrain generator. It will check the queue
  20. # for new requests.
  21. def __init__(self):
  22. threading.Thread.__init__(self)
  23. self.event = threading.Event()
  24. # SRTM downloader. Single instance passed to terrain generator
  25. self.downloader = srtm.SRTMDownloader(debug=False, cachedir='./srtmcache')
  26. self.downloader.loadFileList()
  27. self.terStats = {}
  28. self.terQ = queue.Queue()
  29. def addStatus(self, uuidkey, value):
  30. self.terStats[uuidkey] = value
  31. def run(self):
  32. print("Starting Terrain Generator")
  33. while not self.event.is_set():
  34. time.sleep(0.01)
  35. if not self.terQ.empty():
  36. (radius, lat, lon, spacing, uuidkey, outfolder) = self.terQ.get()
  37. print("Starting request: " + str(uuidkey))
  38. self.terStats[uuidkey] = "Processing"
  39. # generate terrain
  40. makeTerrain(self.downloader, radius, lat, lon, spacing, uuidkey, outfolder)
  41. self.terStats[uuidkey] = "Compressing"
  42. #compress into single file for user
  43. folderthis = os.path.join(os.getcwd(), outfolder + "-tmp", uuidkey)
  44. zipthis = os.path.join(os.getcwd(), outfolder, uuidkey + '.zip')
  45. terrain_zip = zipfile.ZipFile(zipthis, 'w')
  46. print("At Compress ")
  47. #numpercent = numpercent * 1.1
  48. for folder, subfolders, files in os.walk(folderthis):
  49. for file in files:
  50. terrain_zip.write(os.path.join(folder, file), file, compress_type = zipfile.ZIP_DEFLATED)
  51. terrain_zip.close()
  52. #remove old folder
  53. try:
  54. shutil.rmtree(folderthis)
  55. except OSError as e:
  56. print("Error: %s : %s" % (folderthis, e.strerror))
  57. print("At Done")
  58. del self.terStats[uuidkey]
  59. print("Exiting Terrain Generator")
  60. # Terrain generator checker
  61. x = TerGenThread()
  62. x.start()
  63. def queueStatus():
  64. return len(x.terStats)
  65. def wholeStat():
  66. return str(x.terStats)
  67. def shutdown():
  68. x.event.set()
  69. x.join()
  70. @app.route('/')
  71. def index():
  72. return render_template('index.html')
  73. @app.route('/generate', methods = ['GET', 'POST'])
  74. def generate():
  75. if request.method == 'POST':
  76. # parse and sanitise the input
  77. try:
  78. # request.form['username']
  79. lat = float(request.form['lat'])
  80. lon = float(request.form['long'])
  81. radius = int(request.form['radius'])
  82. assert lat < 90
  83. assert lon < 180
  84. assert lat > -90
  85. assert lon > -180
  86. radius = clamp(radius, 1, 400)
  87. except:
  88. print("Bad data")
  89. return render_template('generate.html', error = "Error with input")
  90. # UUID for this terrain generation
  91. uuidkey = str(uuid.uuid1())
  92. # Add this job to the processing queue
  93. x.terQ.put((radius, lat, lon, 100, uuidkey, 'outputTer'))
  94. #x.terStats[uuidkey] = "In Queue, pos={0}".format(terQ.qsize())
  95. x.addStatus(uuidkey, "In Queue, pos={0}".format(x.terQ.qsize()))
  96. return render_template('generate.html', urlkey="/terrain/" + uuidkey + ".zip", waittime=x.terQ.qsize()+1, uuidkey=uuidkey)
  97. else:
  98. print("Bad get")
  99. return render_template('generate.html', error = "Need to use POST, not GET")
  100. @app.route('/status/<uuid:uuidkey>')
  101. def status(uuidkey):
  102. if not uuidkey:
  103. return jsonify(status = 'Error: incorrect UUID')
  104. elif str(uuidkey) in x.terStats:
  105. return jsonify(status = 'success', data = str(x.terStats[str(uuidkey)]))
  106. elif os.path.exists(os.path.join('.', 'outputTer', str(uuidkey) + ".zip")):
  107. return jsonify(status = 'success', data = "ready")
  108. else:
  109. return jsonify(status = 'Error: bad UUID ' + str(os.path.join('.', 'outputTer', str(uuidkey) + ".zip")))