// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

syntax = "proto3";

package grpc.lb.v0;

message Duration {

  // Signed seconds of the span of time. Must be from -315,576,000,000
  // to +315,576,000,000 inclusive.
  int64 seconds = 1;

  // Signed fractions of a second at nanosecond resolution of the span
  // of time. Durations less than one second are represented with a 0
  // `seconds` field and a positive or negative `nanos` field. For durations
  // of one second or more, a non-zero value for the `nanos` field must be
  // of the same sign as the `seconds` field. Must be from -999,999,999
  // to +999,999,999 inclusive.
  int32 nanos = 2;
}

service LoadBalancer {
  // Bidirectional rpc to get a list of servers.
  rpc BalanceLoad(stream LoadBalanceRequest)
      returns (stream LoadBalanceResponse);
}

message LoadBalanceRequest {
  oneof load_balance_request_type {
    // This message should be sent on the first request to the load balancer.
    InitialLoadBalanceRequest initial_request = 1;

    // The client stats should be periodically reported to the load balancer
    // based on the duration defined in the InitialLoadBalanceResponse.
    ClientStats client_stats = 2;
  }
}

message InitialLoadBalanceRequest {
  // Name of load balanced service (IE, service.grpc.gslb.google.com)
  string name = 1;
}

// Contains client level statistics that are useful to load balancing. Each
// count should be reset to zero after reporting the stats.
message ClientStats {
  // The total number of requests sent by the client since the last report.
  int64 total_requests = 1;

  // The number of client rpc errors since the last report.
  int64 client_rpc_errors = 2;

  // The number of dropped requests since the last report.
  int64 dropped_requests = 3;
}

message LoadBalanceResponse {
  oneof load_balance_response_type {
    // This message should be sent on the first response to the client.
    InitialLoadBalanceResponse initial_response = 1;

    // Contains the list of servers selected by the load balancer. The client
    // should send requests to these servers in the specified order.
    ServerList server_list = 2;
  }
}

message InitialLoadBalanceResponse {
  oneof initial_response_type {
    // Contains gRPC config options like RPC deadline or flow control.
    // TODO(yetianx): Change to ClientConfig after it is defined.
    string client_config = 1;

    // This is an application layer redirect that indicates the client should
    // use the specified server for load balancing. When this field is set in
    // the response, the client should open a separate connection to the
    // load_balancer_delegate and call the BalanceLoad method.
    string load_balancer_delegate = 2;
  }

  // This interval defines how often the client should send the client stats
  // to the load balancer. Stats should only be reported when the duration is
  // positive.
  Duration client_stats_report_interval = 3;
}

message ServerList {
  // Contains a list of servers selected by the load balancer. The list will
  // be updated when server resolutions change or as needed to balance load
  // across more servers. The client should consume the server list in order
  // unless instructed otherwise via the client_config.
  repeated Server servers = 1;

  // Indicates the amount of time that the client should consider this server
  // list as valid. It may be considered stale after waiting this interval of
  // time after receiving the list. If the interval is not positive, the
  // client can assume the list is valid until the next list is received.
  Duration expiration_interval = 3;
}

message Server {
  // A resolved address and port for the server. The IP address string may
  // either be an IPv4 or IPv6 address.
  string ip_address = 1;
  int32 port = 2;

  // An opaque token that is passed from the client to the server in metadata.
  // The server may expect this token to indicate that the request from the
  // client was load balanced.
  // TODO(yetianx): Not used right now, and will be used after implementing
  // load report.
  bytes load_balance_token = 3;

  // Indicates whether this particular request should be dropped by the client
  // when this server is chosen from the list.
  bool drop_request = 4;
}
