-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstart_webserver.py
executable file
·305 lines (242 loc) · 10.1 KB
/
start_webserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#!/usr/bin/python
######################################################################
# Simple webserver that runs mission viewer.
#
# REQUIREMENTS: to run this code make sure you have the following
# dependencies:
# sudo pip install -r requirements.txt
#
# HOW TO RUN:
# python start_webserver.py test
# OR
# python start_webserver.py acfrauv
#
# HOW TO TEST:
# If you have the UI code, open a web browser and go to:
# localhost:8080/
# If you do not have the UI code, you can still test that the platform
# data threads are running properly, open a web browser and go to:
# localhost:8080/get_platformdata?platform=0
# where "0" is the ID of the platform you would like to get data for.
# You should see a JSON message containing the data structure that
# should update on refresh.
#
# NOTE:
# If you would like to add your platform to the mission viewer, you
# have come to the right place, but you're in the wrong file.
# For anything basic, you shouldn't need to edit this file. The file
# you are looking for is:
# platformdata_thread.py
#
# That file does all the heavy lifting for platform pose updates.There
# should be enough details in there to help. If it is not obvious please
# contact me.
#
# Author:
# Ariell Friedman
# ariell.friedman@gmail.com
# 25 AUG 2014
#
######################################################################
from flask import Flask, Response, request, render_template, url_for, send_from_directory, redirect #, jsonify
from flask.ext.jsonpify import jsonify # allow cross-domain jsonp messages (for use across the network)
import socket # to get local hostname and ip address easily
import ConfigParser
from osgeo import gdal # for geotiff reading
from PIL import Image # for geotif conversion
import os
import sys
import shutil
from gevent.wsgi import WSGIServer # host it properly
import json
import time
import requests
import threading
app = Flask(__name__)
# import all the worker threads and functions to deal with platform data updates
module = sys.argv[1] if len(sys.argv) > 1 else "test"
port = int(sys.argv[2]) if len(sys.argv) > 2 else 8080
pd = __import__("platformdata.{}".format(module))
pd = getattr(pd, module)
# automatically work out IP address
ipaddress = "%s" % socket.gethostname()
try:
ipaddress = socket.gethostbyname(ipaddress)
except:
pass
thisserver = "http://{}:{}".format(ipaddress, port)
configfile = "config/{}-{}.ini".format(socket.gethostname(),module)
allowadmin = "false"
welcomenote = ""
@app.route('/')
def home():
return render_template('index.html', configfile=configfile, allowadmin=allowadmin, welcomenote=welcomenote)
#return render_template('index.html', server="http://localhost:8080") # server is this machine
@app.route('/get_mission')
def get_mission():
filepath = request.args.get('filepath') # mission file path
olat = request.args.get('olat') #
olon = request.args.get('olon') #
latlngs, origin = pd.parse_mission(filepath, [olat, olon])
return jsonify({"latlngs": latlngs, "origin": origin})
@app.route('/get_geotiff')
def get_geotiff():
# This function needs to get a url for a geotiff, compute the bounds and return the rquired variables as json
url = request.args.get('url')
chartdirurl = 'uploads/geotiffs/'
ds = gdal.Open(url)
gt = ds.GetGeoTransform()
bounds = [
[gt[3], gt[0]],
[gt[3] + ds.RasterXSize*gt[4] + ds.RasterYSize*gt[5], gt[0] + ds.RasterXSize*gt[1] + ds.RasterYSize*gt[2]]
]
# Leaflet cannot display geotiffs in the browser, so we need to convert them to pngs
imgurl = chartdirurl+os.path.basename(url)+'.png'
if not os.path.isfile(imgurl):
Image.open(url).save(imgurl)
return jsonify({'bounds': bounds, 'imgurl': imgurl})
@app.route('/setall_platformdata', methods=['POST'])
def setall_platformdata():
data = request.form.get('platformdata')
pd.set_platformdata(data=data)
return jsonify({"result": "ok"})
@app.route('/set_platformdata', methods=['POST'])
def set_platformdata():
platform = request.args.get('platform')
data = request.form.get('platformdata')
pd.set_platformdata(platform=platform, data=data)
return jsonify({"result": "ok"})
@app.route('/get_platformdata')
def get_platformdata():
# platform as a GET argument
thisplatform = request.args.get('platform')
gethistory = True if request.args.get('gethistory') == "true" else False
# get_platformdata is a function contained in included python script
#print thisplatform, gethistory
return jsonify(pd.get_platformdata(thisplatform, gethistory))
# Custom static data
@app.route('/uploads/<path:filename>')
def serve_uploads(filename):
return send_from_directory('uploads', filename)
@app.route('/get_config', methods=['GET', 'POST'])
def get_config():
cfg = request.args.get('cfg')
if request.method == 'POST':
if allowadmin == "true":
cfgtext = request.form.get('cfgtxt')
open(cfg, 'w').write(cfgtext)
return redirect("/?msg=Config+file+has+been+updated")
else:
sec = request.args.get('sec')
if (not os.path.isfile(cfg)): # copy default config if it doesn't exist
shutil.copy2('{}/template.ini'.format(os.path.dirname(cfg)), cfg)
if sec is None:
action = request.args.get('action')
if action == "getmtime":
return jsonify({'mtime': os.path.getmtime(cfg)})
else:
cfgtext = open(cfg, 'r').read()
form = open('static/html-snippets/form-config.html').read().format(cfg, cfgtext)
return form
else:
config = ConfigParser.ConfigParser()
config.read(cfg)
if sec == "all":
return jsonify(config.sections())
else:
dict = {}
for opt in config.options(sec):
dict[opt] = config.get(sec, opt)
return jsonify(dict)
@app.route('/add_comment', methods=["POST"])
def add_comment():
args = dict(request.form)
return
@app.route('/send_to_platform', methods=["POST"])
def send_to_platform():
# platform as a GET argument
#thisplatform = request.args.get('platform')
args = dict(request.form)
response = pd.send_to_platform(args)
if response == 0:
return jsonify({'response': 'success', 'msg': 'State was set successfully!'})
else:
return redirect({'response': 'error', 'msg': 'There was an error updating the vehicle state file...'})
@app.route('/send_platform_command', methods=["POST"])
def send_platform_command():
args = dict(request.form)
response = pd.send_platform_command(args)
if response == 0:
return jsonify({'response': 'success', 'msg': 'State was set successfully!'})
else:
return redirect({'response': 'error', 'msg': 'There was an error updating the vehicle state file...'})
def get_platform_cmd_form(platform):
return '<div><b><i class="fa fa-gears"></i> Config File Editor</b></div>Command options for: '+platform
class sendRemoteDataThread (threading.Thread):
def __init__(self, delay, targets, destserver):
threading.Thread.__init__(self)
self.delay = delay
self.targets = targets
self.destserver = destserver
self.daemon = True # run in daemon mode to allow for ctrl+C exit
def run(self):
while(1) :
sendplatforms = {}
for key in self.targets:
try:
print 'Getting data for {}'.format(key)
r = requests.get(url=self.targets[key])
if r.status_code == 200:
sendplatforms[key] = json.loads(r.text)
print "Received data for: {}".format(self.targets[key])
except:
print "ERROR!!! Cannot get data for: {}".format(self.targets[key])
try:
print "Sending data to {}".format(self.destserver)
payload = {'platformdata': json.dumps(sendplatforms)}
dirname = "logs/{}".format(time.strftime("%Y/%m/%d"))
filename = "{}/{}-{}.json".format(dirname, module, int(time.time()))
if not os.path.exists(dirname):
os.makedirs(dirname)
f = open(filename, 'w')
f.write(payload['platformdata'])
f.close()
r = requests.post(self.destserver, data=payload)
except:
print "ERROR!!! Unable to send data to {}".format(self.destserver)
time.sleep(self.delay)
def run_server_cfg(configfile):
global allowadmin, welcomenote
cfg = ConfigParser.ConfigParser()
cfg.read(configfile)
if (cfg.has_option('server', 'remotepush')):
remotesecs = cfg.get('server', 'remotepush')
for remotesec in remotesecs.split(','):
remotesec = remotesec.strip()
url = cfg.get(remotesec, 'url')
targets = {}
for k in cfg.get(remotesec, 'targets').split(','):
targets[k] = cfg.get(k, 'url')
if targets[k].find('http://') < 0:
targets[k] = "http://localhost:{}/{}".format(port, targets[k])
#print targets
upddelay = float(cfg.get(remotesec, 'upddelay'))
sendRemoteDataThread(upddelay, targets, url).start()
welcomenote = cfg.get('server','welcomenote') if cfg.has_option('server','welcomenote') else ""
allowadmin = cfg.get('server', 'allowadmin') if (cfg.has_option('server', 'allowadmin')) else "false"
return
if __name__ == '__main__':
# Start threads that do update vehicle data
print "Starting data threads..."
pd.init_platformdata_threads()
run_server_cfg(configfile)
print "Starting webserver..."
print "To connect to this server from another machine on the network, open a browser and go to: \n\n {}\n".format(thisserver)
#print app.config
# app.run(
# #debug = True,
# host = "0.0.0.0",
# port = 8080
# )
http_server = WSGIServer(('', port), app)
http_server.serve_forever()