def process_POST(self, request): """ Function that will be called upon receiving a POST request for the aforementioned URL. """ # Parse the given parameters. event_id = request.args0.get("event", None) is_synthetic = request.args0.get("synthetic", None) tag = request.args0.get("tag", "") if isinstance(is_synthetic, basestring) and \ is_synthetic.lower() in lowercase_true_strings: is_synthetic = True else: is_synthetic = False # Every waveform MUST be bound to an event. if event_id is None: msg = ("No event parameter passed. Every waveform " "must be bound to an existing event.") raise InvalidParameterError(msg) if not event_exists(event_id, self.env): msg = "The given event resource name '%s' " % event_id msg += "is not known to SeisHub." raise InvalidParameterError(msg) # There are two possibilities for getting data inside the database: # upload the file directly to SeisHub or just give a file URL that the # server can find. filename = request.args0.get("index_file", None) # If the 'index_file' parameter is not given, assume the file will be # directly uploaded. if filename is None: waveform_data = request.content waveform_data.seek(0, 0) file_is_managed_by_seishub = True else: filename = os.path.abspath(filename) if not os.path.exists(filename) or \ not os.path.isfile(filename): msg = "File '%s' cannot be found by the SeisHub server." % \ filename raise InvalidParameterError(msg) with open(filename, "rb") as open_file: waveform_data = StringIO(open_file.read()) waveform_data.seek(0, 0) file_is_managed_by_seishub = False # Check if file exists. Checksum is returned otherwise. Raises on # failure. data = waveform_data.read() waveform_data.seek(0, 0) md5_hash = check_if_file_exist_in_db(data, self.env) msg = ("The data does not appear to be a valid waveform file. Only " "data readable by ObsPy is acceptable.") # Only valid waveforms files will be stored in the database. Valid is # defined by being readable by ObsPy. try: st = read(waveform_data) except: raise InvalidObjectError(msg) # Replace network, station and channel codes with placeholders if they # do not exist. Location can be an empty string. network = st[0].stats.network if st[0].stats.network else "XX" station = st[0].stats.station if st[0].stats.station else "XX" location = st[0].stats.location channel = st[0].stats.channel if st[0].stats.channel else "XX" # Check if the tag is valid, e.g. that it fulfulls the constraints of # being unique per channel_id and event. tags = get_all_tags(network, station, location, channel, event_id, self.env) if tag in tags: msg = "Tag already exists for the given channel id and event." raise InvalidParameterError(msg) if file_is_managed_by_seishub is True: # Otherwise create the filename for the file, and check if it # exists. filename = os.path.join(self.env.config.get("event_based_data", "waveform_filepath"), event_id, ("{network}.{station}.{location}.{channel}-" "{year}_{month}_{day}_{hour}")) t = st[0].stats.starttime filename = filename.format(network=network, station=station, channel=channel, location=location, year=t.year, month=t.month, day=t.day, hour=t.hour) # Write the data to the filesystem. The final filename is returned. filename = write_string_to_filesystem(filename, data) # Use only one session to be able to take advantage of transactions. session = self.env.db.session(bind=self.env.db.engine) # Wrap in try/except and rollback changes in case something fails. try: # Add information about the uploaded file into the database. filepath = add_filepath_to_database(session, filename, len(data), md5_hash, is_managed_by_seishub=file_is_managed_by_seishub) # Loop over all traces in the file. for trace in st: stats = trace.stats # Extract coordinates if it is a sac file. Else set them to # None. if hasattr(stats, "sac"): # Invalid floating point value according to the sac # definition. iv = -12345.0 sac = stats.sac latitude = sac.stla if sac.stla != iv else None longitude = sac.stlo if sac.stlo != iv else None elevation = sac.stel if sac.stel != iv else None local_depth = sac.stdp if sac.stdp != iv else None else: latitude, longitude, elevation, local_depth = [None] * 4 # Add the channel if it does not already exists, or update the # location or just return the existing station. In any case a # channel column object will be returned. channel_row = add_or_update_channel(session, stats.network, stats.station, stats.location, stats.channel, latitude, longitude, elevation, local_depth) # Add the current waveform channel as well. waveform_channel = WaveformChannelObject( channel=channel_row, filepath=filepath, event_resource_id=event_id, starttime=stats.starttime.datetime, endtime=stats.endtime.datetime, tag=tag, sampling_rate=stats.sampling_rate, format=stats._format, is_synthetic=is_synthetic) session.add(waveform_channel) session.commit() except Exception, e: # Rollback session. session.rollback() session.close() # Remove the file if something failes.. if file_is_managed_by_seishub: os.remove(filename) msg = e.message + " - Rolling back all changes." raise InternalServerError(msg)
def process_POST(self, request): """ Function that will be called upon receiving a POST request for the aforementioned URL. """ # There are two possibilities for getting data inside the database: # upload the file directly to SeisHub or just give a file URL that the # server can find. filename = request.args0.get("index_file", None) # If the 'index_file' parameter is not given, assume the file will be # directly uploaded. if filename is None: station_data = request.content station_data.seek(0, 0) file_is_managed_by_seishub = True else: filename = os.path.abspath(filename) if not os.path.exists(filename) or not os.path.isfile(filename): msg = "File '%s' cannot be found by the SeisHub server." % \ filename raise InvalidParameterError(msg) with open(filename, "rb") as open_file: station_data = StringIO.StringIO(open_file.read()) station_data.seek(0, 0) file_is_managed_by_seishub = False # Check if file exists. Checksum is returned otherwise. Raises on # failure. data = station_data.read() station_data.seek(0, 0) md5_hash = check_if_file_exist_in_db(data, self.env) # Attempt to read as a SEED/XSEED file. station_data.seek(0, 0) channels = _read_SEED(station_data) station_data.seek(0, 0) # Otherwise attempt to read as a RESP file. if channels is False: channels = _read_RESP(station_data) # Otherwise raise an Error. if channels is False: msg = "Could not read the station information file." raise InvalidObjectError(msg) if file_is_managed_by_seishub is True: network = channels[0]["network"] filename = os.path.join(self.env.config.get("event_based_data", "station_filepath"), network, ("{network}.{station}.{location}.{channel}-" "{year}_{month}")) filename = filename.format(network=network, station=channels[0]["station"], location=channels[0]["location"], channel=channels[0]["channel"], year=channels[0]["start_date"].year, month=channels[0]["start_date"].month) # Write the data to the filesystem. The final filename is returned. filename = write_string_to_filesystem(filename, data) # Use only one session to be able to take advantage of transactions. session = self.env.db.session(bind=self.env.db.engine) # Wrap in try/except and rollback changes in case something fails. try: # Add information about the uploaded file into the database. filepath = add_filepath_to_database(session, filename, len(data), md5_hash, is_managed_by_seishub=file_is_managed_by_seishub) # Loop over all channels. for channel in channels: # Add the channel if it does not already exists, or update the # location or just return the existing station. In any case a # channel column object will be returned. channel_row = add_or_update_channel(session, channel["network"], channel["station"], channel["location"], channel["channel"], channel["latitude"], channel["longitude"], channel["elevation"], channel["local_depth"], force_update=True) # Now add information about the time span of the current # channel information. if hasattr(channel["end_date"], "datetime"): end_date = channel["end_date"].datetime else: end_date = None metadata = ChannelMetadataObject(channel=channel_row, filepath=filepath, starttime=channel["start_date"].datetime, endtime=end_date, format=channel["format"]) session.add(metadata) session.commit() except Exception, e: # Rollback session. session.rollback() session.close() # Attempt to return a meaningfull error message. msg = ("(%s) " % e.__class__.__name__) + e.message + \ " -- Rolling back all changes." # It is possible that two files with different hashes contain # information about exactly the same time span. In this case the # uniqueness constrains of the database will complain and an # integrity error will be raised. Catch it to give a meaningful # error message. if isinstance(e, IntegrityError) and hasattr(channel, "starttime"): msg = ("\nThe information for the following timespan is " "already existant in the database:\n") msg += "%s.%s.%s.%s - %s-%s\n" % (channel["network"], channel["station"], channel["location"], channel["channel"], str(channel["starttime"]), str(channel["endtime"])) msg += ("All information contained in this file will not be " "added to the database.") # Remove the file if something failed. if file_is_managed_by_seishub is True: os.remove(filename) self.env.log.error(msg) raise InternalServerError(msg)