// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.

syntax = "proto3";
option go_package = "storj.io/common/pb";

import "gogo.proto";
import "google/protobuf/timestamp.proto";
import "metainfo.proto";
import "orders.proto";

package gracefulexit;

service SatelliteGracefulExit {
  // Process is called by storage nodes to initiate the graceful exit, get pieces to transfer, and receive exit status.
  rpc Process(stream StorageNodeMessage) returns (stream SatelliteMessage);
  // GracefulExitFeasibility returns node's join date and satellites config's amount of months required for graceful exit to be allowed.
  rpc GracefulExitFeasibility(GracefulExitFeasibilityRequest) returns (GracefulExitFeasibilityResponse);
}

message GracefulExitFeasibilityRequest {}

message GracefulExitFeasibilityResponse {
    google.protobuf.Timestamp joined_at = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
    int32 months_required = 2;
    bool is_allowed = 3;
}

message TransferSucceeded {
  orders.OrderLimit            original_order_limit    = 1;
  orders.PieceHash             original_piece_hash     = 2;
  orders.PieceHash             replacement_piece_hash  = 3;
  bytes                        original_piece_id       = 4 [(gogoproto.customtype) = "PieceID", (gogoproto.nullable) = false];
}

message TransferFailed {
  bytes original_piece_id    = 1 [(gogoproto.customtype) = "PieceID", (gogoproto.nullable) = false];
  enum Error {
      NOT_FOUND                 = 0;
      STORAGE_NODE_UNAVAILABLE  = 1;
      HASH_VERIFICATION         = 2;

      UNKNOWN                   = 10;
  }
  Error error = 2;
}

message StorageNodeMessage {
  oneof Message {
    TransferSucceeded succeeded = 1;
    TransferFailed    failed    = 2;
  }
}

message NotReady {}

message TransferPiece {
  bytes original_piece_id    = 1 [(gogoproto.customtype) = "PieceID", (gogoproto.nullable) = false];
  bytes private_key = 2 [(gogoproto.customtype) = "PiecePrivateKey", (gogoproto.nullable) = false];

  // addressed_order_limit contains the new piece id.
  metainfo.AddressedOrderLimit addressed_order_limit =3;
}

message DeletePiece {
  bytes original_piece_id = 1 [(gogoproto.customtype) = "PieceID", (gogoproto.nullable) = false];
}

message ExitCompleted {
  // when everything is completed
  bytes exit_complete_signature = 1;
  // satellite who issued this exit completed
  bytes satellite_id = 2 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false];
  // storage node this exit completed was issued to
  bytes node_id = 3 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false];
  // timestamp when the exit completed
  google.protobuf.Timestamp completed = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];  
}

message ExitFailed {
  enum Reason {
      VERIFICATION_FAILED = 0;
      INACTIVE_TIMEFRAME_EXCEEDED = 1;
      OVERALL_FAILURE_PERCENTAGE_EXCEEDED = 2;
  }
  // on failure
  bytes exit_failure_signature  = 1;
  Reason reason                 = 2;
  // satellite who issued this exit failed
  bytes satellite_id = 3 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false];
  // storage node this exit failed was issued to
  bytes node_id = 4 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false];
  // timestamp when the exit failed
  google.protobuf.Timestamp failed = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];  
}

message SatelliteMessage {
  oneof Message {
    NotReady      not_ready       = 1;
    TransferPiece transfer_piece  = 2;
    DeletePiece   delete_piece    = 3;
    ExitCompleted exit_completed  = 4;
    ExitFailed    exit_failed     = 5;
  }
}

