Exemplo n.º 1
0
def poll_display_data(dp_id: str) -> Tuple[str, int]:
  """Implements display data polling in RID automated testing observation API."""

  # TODO: Validate token signature & scope

  # Retrieve view parameters
  if 'view' not in flask.request.args:
    return 'Missing "view" argument in request', 400

  try:
    coords = [float(v) for v in flask.request.args['view'].split(',')]
  except ValueError as e:
    return '"view" argument not properly formatted: {}'.format(e), 400

  if len(coords) != 4:
    return '"view" argument contains the wrong number of coordinates (expected 4, found {})'.format(len(coords)), 400

  lat_min = min(coords[0], coords[2])
  lat_max = max(coords[0], coords[2])
  lng_min = min(coords[1], coords[3])
  lng_max = max(coords[1], coords[3])

  if (lat_min < -90 or lat_min >= 90 or lat_max <= -90 or lat_max > 90 or
    lng_min < -180 or lng_min >= 360 or lng_max <= -180 or lng_max > 360):
    return '"view" coordinates do not fall within the valid range of -90 <= lat <= 90 and -180 <= lng <= 360', 400

  # Check view size
  view_min = s2sphere.LatLng.from_degrees(lat_min, lng_min)
  view_max = s2sphere.LatLng.from_degrees(lat_max, lng_max)
  diagonal = view_min.get_distance(view_max).degrees * geo.EARTH_CIRCUMFERENCE_KM / 360
  if diagonal > 3.6:
    return flask.jsonify(rid.ErrorResponse(message='Requested diagonal was too large')), 413

  # Get Display Provider behavior
  dp_behavior = db.get_dp(dp_id).behavior

  # Find flights to report
  t_now = datetime.datetime.now(datetime.timezone.utc)
  t_earliest = t_now - datetime.timedelta(seconds=60)
  flights: List[observation_api.Flight] = []
  for sp_id, sp in db.sps.items():
    if sp_id in dp_behavior.do_not_display_flights_from:
      continue
    sp_behavior = db.get_sp(sp_id).behavior
    for test_id, test in sp.tests.items():
      for flight in test.flights:
        flights.append(_make_api_flight(
          flight, sp_behavior, dp_behavior, t_earliest, t_now,
          lat_min, lng_min, lat_max, lng_max))
  flights = [flight for flight in flights if 'most_recent_position' in flight]

  if diagonal <= 1:
    return flask.jsonify(observation_api.GetDisplayDataResponse(flights=flights))
  else:
    return flask.jsonify(observation_api.GetDisplayDataResponse(clusters=clustering.make_clusters(flights, view_min, view_max)))
Exemplo n.º 2
0
def display_data() -> Tuple[str, int]:
    """Implements retrieval of current display data per automated testing API."""

    if 'view' not in flask.request.args:
        return flask.jsonify(
            rid.ErrorResponse(
                message='Missing required "view" parameter')), 400
    try:
        view = geo.make_latlng_rect(flask.request.args['view'])
    except ValueError as e:
        return flask.jsonify(
            rid.ErrorResponse(message='Error parsing view: {}'.format(e))), 400

    # Determine what kind of response to produce
    diagonal = geo.get_latlngrect_diagonal_km(view)
    if diagonal > rid.NetMaxDisplayAreaDiagonal:
        return flask.jsonify(
            rid.ErrorResponse(message='Requested diagonal was too large')), 413

    # Get ISAs in the DSS
    t = arrow.utcnow().datetime
    isas_response: fetch.FetchedISAs = fetch.isas(resources.utm_client, view,
                                                  t, t)
    if not isas_response.success:
        response = rid.ErrorResponse(message='Unable to fetch ISAs from DSS')
        response['errors'] = [isas_response]
        return flask.jsonify(response), 412

    # Fetch flights from each unique flights URL
    validated_flights: List[rid.RIDFlight] = []
    tx = db.value
    flight_info: Dict[str, database.FlightInfo] = {
        k: v
        for k, v in tx.flights.items()
    }

    for flights_url in isas_response.flight_urls:
        flights_response = fetch.flights(resources.utm_client, flights_url,
                                         view, True)
        if not flights_response.success:
            response = rid.ErrorResponse(
                message='Error querying {}'.format(flights_url))
            response['errors'] = [flights_response]
            return flask.jsonify(response), 412
        for flight in flights_response.flights:
            try:
                validated_flight: rid.RIDFlight = ImplicitDict.parse(
                    flight, rid.RIDFlight)
            except ValueError as e:
                response = rid.ErrorResponse(
                    message='Error parsing flight from {}'.format(flights_url))
                response['parse_error'] = str(e)
                response['flights'] = flights_response.flights
                return flask.jsonify(response), 412
            validated_flights.append(validated_flight)
            flight_info[flight.id] = database.FlightInfo(
                flights_url=flights_url)

    if diagonal <= rid.NetDetailsMaxDisplayAreaDiagonal:
        # Construct detailed flights response
        response = observation_api.GetDisplayDataResponse(flights=[
            _make_flight_observation(f, view) for f in validated_flights
        ])
        with db as tx:
            for k, v in flight_info.items():
                tx.flights[k] = v
        return flask.jsonify(response)
    else:
        # Construct clusters response
        return 'Cluster response not yet implemented', 500