コード例 #1
0
    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)
コード例 #2
0
    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)