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

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

package piecestore;

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

service Piecestore {
    rpc Upload(stream PieceUploadRequest) returns (PieceUploadResponse) {}
    rpc Download(stream PieceDownloadRequest) returns (stream PieceDownloadResponse) {}
    rpc Delete(PieceDeleteRequest) returns (PieceDeleteResponse) {
      option deprecated = true;
    }
    // DeletePieces deletes a set of pieces on satellite request
    rpc DeletePieces(DeletePiecesRequest) returns (DeletePiecesResponse);
    rpc Retain(RetainRequest) returns (RetainResponse);

    // RetainBig is the same as the Retain, but can receive multiple messages with different part of the bloom filter.
    // last message should contain hash.
    rpc RetainBig(stream RetainRequest) returns (RetainResponse);
    rpc RestoreTrash(RestoreTrashRequest) returns (RestoreTrashResponse) {}
    // Exists checks if requested pieces exists on storage node. Will check only
    // pieces which belongs to the satellite that call this method.
    rpc Exists(ExistsRequest) returns (ExistsResponse);
}

// Expected order of messages from uplink:
//
//   OrderLimit ->
//   repeated
//      Order ->
//      Chunk ->
//   PieceHash signed by uplink ->
//      <- PieceHash signed by storage node
message PieceUploadRequest {
    // first message to show that we are allowed to upload
    orders.OrderLimit limit = 1;

    // first message must have it if (!) not the default sha256 is used, as it
    // should be initialized by the storagenode before upload.
    // should match with the algorithm in the done field of the last message
    orders.PieceHashAlgorithm hash_algorithm = 5;

    // order for uploading
    orders.Order      order = 2;

    // data message
    message Chunk {
        int64 offset = 1;
        bytes data = 2;
    }
    Chunk      chunk = 3;
    // final message
    orders.PieceHash done = 4;
}

message PieceUploadResponse {
    orders.PieceHash done = 1;
    // this is for validating the PieceHash signature if the cert chain is
    // unable to be pulled off the connection (Noise instead of TLS).
    bytes node_certchain = 2;
}

// Expected order of messages from uplink:
//
//   {OrderLimit, Chunk} ->
//   go repeated
//      Order -> (async)
//   go repeated
//      <- PieceDownloadResponse.Chunk
message PieceDownloadRequest {
    // first message to show that we are allowed to upload
    orders.OrderLimit limit = 1;
    // order for downloading
    orders.Order      order = 2;

    // Chunk that we wish to download
    message Chunk {
        int64 offset = 1;
        int64 chunk_size = 2;
    }

    // request for the chunk
    Chunk chunk = 3;

    // maximum_chunk_size is an advisory request from the uplink to
    // the storage node on how big the chunks should be. smaller
    // maximum sizes may reduce time to first byte and peak memory usage.
    int32 maximum_chunk_size = 4;
}

message PieceDownloadResponse {
    // Chunk response for download request
    message Chunk {
        int64 offset = 1;
        bytes data = 2;
    }
    Chunk chunk = 1;
    orders.PieceHash hash = 2;
    orders.OrderLimit limit = 3;
    bool restored_from_trash = 4;
}

message PieceDeleteRequest {
    orders.OrderLimit limit = 1;
}

message PieceDeleteResponse {
}

message DeletePiecesRequest {
    repeated bytes piece_ids = 1 [(gogoproto.customtype) = "PieceID", (gogoproto.nullable) = false];
}

message DeletePiecesResponse {
    int64 unhandled_count = 1;
}


// RetainRequest contains bloom filter. It's either sent together (time + filter) or in multiple chunks, where
// first message contains time + first part of the filter, and the last part contains the hash (to double check if all pieces are arrived).
message RetainRequest {
    google.protobuf.Timestamp creation_date = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
    bytes filter = 2;
    orders.PieceHashAlgorithm hash_algorithm = 3;
    bytes hash = 4;
}

message RetainResponse {
}

message RestoreTrashRequest {}
message RestoreTrashResponse {}

// PieceHeader is used in piece storage to keep track of piece attributes.
message PieceHeader {
    enum FormatVersion {
        FORMAT_V0 = 0;
        FORMAT_V1 = 1;
    }
    // the storage format version being used for this piece. The piece filename should agree with this.
    // The inclusion of this field is intended to aid repairability when filenames are damaged.
    FormatVersion format_version = 1;
    // content hash of the piece
    bytes hash = 2;
    // the algorithm of the hash
    orders.PieceHashAlgorithm hash_algorithm = 6;

    // timestamp when upload occurred, as given by the "timestamp" field in the original orders.PieceHash
    google.protobuf.Timestamp creation_time = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
    // signature from uplink over the original orders.PieceHash (the corresponding PieceHashSigning
    // is reconstructable using the piece id from the piecestore, the piece size from the
    // filesystem (minus the piece header size), and these (hash, upload_time, signature) fields).
    bytes signature = 4;
    // the OrderLimit authorizing storage of this piece, as signed by the satellite and sent by
    // the uplink
    orders.OrderLimit order_limit = 5 [(gogoproto.nullable) = false];
}

message ExistsRequest {
    repeated bytes piece_ids = 1 [(gogoproto.customtype) = "PieceID", (gogoproto.nullable) = false];
}

message ExistsResponse {
    // input piece ids indices of the missing pieces
    repeated uint32 missing = 1;
}
