-
Notifications
You must be signed in to change notification settings - Fork 2
/
api.py
196 lines (158 loc) · 5.88 KB
/
api.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
import os
import sys
import redis
import logging
import ephem
import requests
from flask import Flask, render_template, redirect, jsonify
from json import loads, dumps
from util import json, jsonp, support_jsonp
from scrapers.dsn import get_dsn_raw
app = Flask(__name__)
REDIS_URL = os.getenv('REDISTOGO_URL', 'redis://localhost:6379')
r_server = redis.StrictRedis.from_url(REDIS_URL)
app.logger.addHandler(logging.StreamHandler(sys.stdout))
app.logger.setLevel(logging.ERROR)
@app.route('/')
def hello():
return redirect("/dsn/probes.json", code=302)
@app.route('/dsn/mirror.json')
@json
def dsn_mirror():
""" a json view of the dsn xml feed """
dsn = loads(r_server.get('dsn_raw'))
return {'dsn': dsn }, 200
@app.route('/dsn/probes.json')
@app.route('/dsn/spaceprobes.json')
@support_jsonp
def dsn_by_probe():
""" dsn data aggregated by space probe """
dsn_by_probe = loads(r_server.get('dsn_by_probe'))
return jsonify({'dsn_by_probe': dsn_by_probe})
# for feeding the spaceprobes website
@app.route('/distances.json')
@support_jsonp
def all_probe_distances():
"""
endpoint to feed the spaceprobes website
this endpoint firsts asks the website what spaceprobes it has
and returns something for each. maybe this is a feature?
to test locally, edit the url below
and in the spaceprobes site main.js edit the distances_feed_url
you might also need to grab copy of this app's redis db from
heroku production to build locally
"""
# first get list of all probes from the webiste
url = 'http://spaceprob.es/probes.json'
all_probes_website = loads(requests.get(url).text)
# get probes according to our DSN mirror
dsn = loads(r_server.get('dsn_by_probe'))
# now loop through probes on website and try to find their distances
# some will have distances in dsn feed, others will have resource from website endpoint
# and others we will use pyephem for their host planet
distances = {}
for probe in all_probes_website:
dsn_name = probe['dsn_name']
slug = probe['slug']
if dsn_name and dsn_name in dsn:
try:
distances[slug] = dsn[dsn_name]['uplegRange']
except KeyError:
try:
distances[slug] = dsn[dsn_name]['downlegRange']
except KeyError:
# there is no distance data
continue
elif 'orbit_planet' in probe and probe['orbit_planet']:
# this probe's distance is same as a planet, so use pyephem
if probe['orbit_planet'] == 'Venus':
m = ephem.Venus()
if probe['orbit_planet'] == 'Mars':
m = ephem.Mars()
if probe['orbit_planet'] == 'Moon':
m = ephem.Moon()
if probe['orbit_planet'] == 'Earth-Moon-L2':
m = ephem.Moon()
if m:
m.compute()
earth_distance = m.earth_distance * 149597871 # convert from AU to kilometers
if probe['orbit_planet'] == 'Earth-Moon-L2':
earth_distance = earth_distance + 72000 # approximation for E-M L2
# Queqiao orbits around Earth-Moon L2, which is distance of the
# Moon plus 65,000-80,000km
distances[slug] = str(earth_distance)
elif 'distance' in probe and probe['distance']:
# this probe's distance is hard coded at website, add that
try:
# make sure this is actually numeric
float(probe['distance'])
distances[slug] = str(probe['distance'])
except ValueError:
pass
return jsonify({'spaceprobe_distances': distances})
@app.route('/planets.json')
@support_jsonp
def planet_distances():
""" return current distances from earth for 9 planets """
meters_per_au = 149597870700
planet_ephem = [ephem.Mercury(), ephem.Venus(), ephem.Mars(), ephem.Saturn(), ephem.Jupiter(), ephem.Uranus(), ephem.Neptune(), ephem.Pluto()]
planets = {}
for p in planet_ephem:
p.compute()
planets[p.name] = p.earth_distance * meters_per_au / 10000 # km
return jsonify({'distance_from_earth_km': planets})
# the rest of this is old and like wolfram alpha hacking or something..
def get_detail(probe):
""" returns list of data we have for this probe
url = /<probe_name>
"""
try:
wolframalpha = loads(r_server.get('wolframalpha'))
detail = wolframalpha[probe]
return detail
except TypeError: # type error?
return {'Error': 'spacecraft not found'}, 404 # this doesn't work i dunno
@app.route('/probes/guide/')
def guide():
""" html api guide data viewer thingy
at </probes/guide/>
"""
try:
wolframalpha = loads(r_server.get('wolframalpha'))
kwargs = {'probe_details':wolframalpha}
return render_template('guide.html', **kwargs)
except:
return redirect("dsn/probes.json", code=302)
@app.route('/probes/<probe>/')
@support_jsonp
@json
def detail(probe):
""" returns list of data we have for this probe from wolfram alpha
url = /<probe_name>
ie
</Cassini>
"""
return get_detail(probe), 200
@app.route('/probes/<probe>/<field>/')
@support_jsonp
@json
def single_field(probe, field):
""" returns data for single field
url = /<probe_name>/<field>
ie
</Cassini/mass>
"""
field_value = get_detail(probe)
return {field: field_value[field]}, 200
@app.route('/probes/')
@support_jsonp
@json
def index():
""" returns list of all space probes in db
url = /
"""
probe_names = [k for k in loads(r_server.get('wolframalpha'))]
return {'spaceprobes': [p for p in probe_names]}, 200
if __name__ == '__main__':
app.debug = True
app.run()