Newer
Older
"""WSGI implementation of Intermagnet Web Service
"""
from __future__ import print_function
from cgi import parse_qs, escape
from datetime import datetime
from geomagio.edge import EdgeFactory
from geomagio.iaga2002 import IAGA2002Writer
from obspy.core import UTCDateTime
DEFAULT_ELEMENTS = ('X', 'Y', 'Z', 'F')
DEFAULT_PERIOD = '60'
DEFAULT_TYPE = 'variation'
VALID_TYPES = [
'variation',
'adjusted',
'quasi-definitive',
'definitive'
]
VALID_PERIODS = ['1', '60']
VALID_FORMATS = ['iaga2002']
class WebService(object):
def __init__(self, factory):
self.factory = factory
def __call__(self, environ, start_response):
"""Implement WSGI interface"""
# parse params
query = WebServiceQuery.parse(environ['QUERY_STRING'])
data = self.fetch(query)
# format data
data_string = self.format(query, data)
if isinstance(data_string, str):
data_string = data_string.encode('utf8')
# send response
start_response('200 OK',
[
("Content-Type", "text/plain")
])
return [data_string]
def fetch(self, query):
"""Get requested data.
Parameters
----------
query : dictionary of parsed query parameters
Returns
-------
obspy.core.Stream
timeseries object with requested data.
"""
data = self.factory.get_timeseries(
observatory=query.id,
channels=query.elements,
starttime=query.starttime,
endtime=query.endtime,
type=query.type,
interval=query.sampling_period)
return data
def format(self, query, data):
"""Format requested data.
Parameters
----------
query : dictionary of parsed query parameters
data : obspy.core.Stream
timeseries object with data to be written
Returns
-------
unicode
IMFJSON or IAGA2002 formatted string.
"""
# TODO: Add option for json format
data_string = IAGA2002Writer.format(data, query.elements)
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
class WebServiceQuery(object):
"""Query parameters for a web service request.
Parameters
----------
id : str
observatory
starttime : obspy.core.UTCDateTime
time of first requested sample
endtime : obspy.core.UTCDateTime
time of last requested sample
elements : array_like
list of requested elements
sampling_period : int
period between samples in seconds
default 60.
type : {'variation', 'adjusted', 'quasi-definitive', 'definitive'}
data type
default 'variation'.
format : {'iaga2002', 'json'}
output format.
default 'iaga2002'.
"""
def __init__(self, id=None, starttime=None, endtime=None, elements=None,
sampling_period=60, type='variation', format='iaga2002'):
self.id = id
self.starttime = starttime
self.endtime = endtime
self.elements = elements
self.sampling_period = sampling_period
self.type = type
self.format = format
@classmethod
def parse(cls, params):
"""Parse query string parameters and set defaults.
Parameters
----------
Returns
-------
WebServiceQuery
parsed query object.
Raises
------
TimeseriesFactoryException
if id, type, sampling_period, or format are not supported.
"""
# Create dictionary of lists
dict = parse_qs(params)
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
# Get values
if len(dict.get('id', [])) <= 1:
id = dict.get('id', [''])[0]
else:
raise WebServiceException(
'"id" accepts only one value')
if len(dict.get('starttime', [])) <= 1:
starttime = dict.get('starttime', [''])[0]
else:
raise WebServiceException(
'"starttime" accepts only one value')
if len(dict.get('endtime', [])) <= 1:
endtime = dict.get('endtime', [''])[0]
else:
raise WebServiceException(
'"endtime" accepts only one value')
if len(dict.get('elements', [])) <= 1:
elements = dict.get('elements', [''])[0]
else:
raise WebServiceException(
'"elements" accepts only one set of values')
if len(dict.get('sampling_period', [])) <= 1:
sampling_period = dict.get('sampling_period', [''])[0]
else:
raise WebServiceException(
'"sampling_period" accepts only one value')
if len(dict.get('type', [])) <= 1:
type = dict.get('type', [''])[0]
else:
raise WebServiceException(
'"type" accepts only one value')
if len(dict.get('format', [])) <= 1:
format = dict.get('format', [''])[0]
else:
raise WebServiceException(
'"format" accepts only one value')
id = escape(id)
starttime = escape(starttime)
endtime = escape(endtime)
sampling_period = escape(sampling_period)
type = escape(type).lower()
format = escape(format)
# Check for parameters and set defaults
if not id:
raise WebServiceException(
'"id" is a required parameter')
if starttime:
try:
starttime = UTCDateTime(starttime)
except:
raise WebServiceException(
'Invalid starttime "%s"' % starttime)
else:
year=now.year,
month=now.month,
day=now.day,
hour=0)
if endtime:
try:
endtime = UTCDateTime(endtime)
except:
raise WebServiceException(
'Invalid endtime "%s"' % endtime)
else:
endtime = starttime + (24 * 60 * 60 - 1)
if starttime > endtime:
'Starttime before endtime "%s" "%s"'
% (starttime, endtime))
elements = [el.strip().upper() for el in elements.split(',')]
else:
elements = DEFAULT_ELEMENTS
sampling_period = DEFAULT_PERIOD
if sampling_period not in VALID_PERIODS:
'Invalid sampling period.'
' Valid sampling periods: %s' % VALID_PERIODS)
if sampling_period == '1':
sampling_period = 'second'
if sampling_period == '60':
sampling_period = 'minute'
if not type:
type = DEFAULT_TYPE
if type not in VALID_TYPES:
'Invalid data type.'
' Valid data types: %s' % VALID_TYPES)
# TODO: Add json to valid formats
if not format:
format = 'iaga2002'
if format not in VALID_FORMATS:
'Invalid format.'
' Valid formats: %s' % VALID_FORMATS)
# Create WebServiceQuery object and set properties
query = WebServiceQuery
query.id = id
query.starttime = starttime
query.endtime = endtime
query.elements = elements
query.sampling_period = sampling_period
query.type = type
query.format = format
return query
class WebServiceException(Exception):
"""Base class for exceptions thrown by web services."""
pass
if __name__ == '__main__':
from wsgiref.simple_server import make_server
app = WebService(EdgeFactory())
httpd = make_server('', 8080, app)
httpd.serve_forever()