syntax = "proto3";
package object;
option go_package = "github.com/nspcc-dev/neofs-proto/object";

import "refs/types.proto";
import "object/types.proto";
import "session/types.proto";
import "service/meta.proto";
import "service/verify.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

option (gogoproto.stable_marshaler_all) = true;

// Object service provides API for manipulating with the object.
service Service {

    // Get the object from container. Response uses gRPC stream. First response
    // message carry object of requested address. Chunk messages are parts of
    // the object's payload if it is needed. All messages except first carry
    // chunks. Requested object can be restored by concatenation of object
    // message payload and all chunks keeping receiving order.
    rpc Get(GetRequest) returns (stream GetResponse);

    // Put the object into container. Request uses gRPC stream. First message
    // SHOULD BE type of PutHeader. Container id and Owner id of object SHOULD
    // BE set. Session token SHOULD BE obtained before put operation (see
    // session package). Chunk messages considered by server as part of object
    // payload. All messages except first SHOULD BE chunks. Chunk messages
    // SHOULD BE sent in direct order of fragmentation.
    rpc Put(stream PutRequest) returns (PutResponse);

    // Delete the object from a container
    rpc Delete(DeleteRequest) returns (DeleteResponse);

    // Head returns the object without data payload. Object in the
    // response has system header only. If full headers flag is set, extended
    // headers are also present.
    rpc Head(HeadRequest) returns (HeadResponse);

    // Search objects in container. Version of query language format SHOULD BE
    // set to 1. Search query represented in serialized format (see query
    // package).
    rpc Search(SearchRequest) returns (SearchResponse);

    // GetRange of data payload. Ranges are set of pairs (offset, length).
    // Fragments order in response corresponds to ranges order in request.
    rpc GetRange(GetRangeRequest) returns (GetRangeResponse);

    // GetRangeHash returns homomorphic hash of object payload range after XOR
    // operation. Ranges are set of pairs (offset, length). Hashes order in
    // response corresponds to ranges order in request. Homomorphic hash is
    // calculated for XORed data.
    rpc GetRangeHash(GetRangeHashRequest) returns (GetRangeHashResponse);
}

message GetRequest {
    // Address of object (container id + object id)
    refs.Address Address                     = 1 [(gogoproto.nullable) = false];
    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}

message GetResponse {
    oneof R {
        // Object header and some payload
        Object object = 1;
        // Chunk of remaining payload
        bytes Chunk   = 2;
    }
}

message PutRequest {
    message PutHeader {
        // Object with at least container id and owner id fields
        Object Object       = 1;
        // Token with session public key and user's signature
        session.Token Token = 2;
    }

    oneof R {
        // Header should be the first message in the stream
        PutHeader Header = 1;
        // Chunk should be a remaining message in stream should be chunks
        bytes Chunk      = 2;
    }

    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}

message PutResponse {
    // Address of object (container id + object id)
    refs.Address Address = 1 [(gogoproto.nullable) = false];
}
message DeleteRequest {
    // Address of object (container id + object id)
    refs.Address Address                     = 1 [(gogoproto.nullable) = false];
    // OwnerID is a wallet address
    bytes OwnerID                            = 2 [(gogoproto.nullable) = false, (gogoproto.customtype) = "OwnerID"];
    // Token with session public key and user's signature
    session.Token Token                      = 3;
    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}

// DeleteResponse is empty because we cannot guarantee permanent object removal
// in distributed system.
message DeleteResponse {}

message HeadRequest {
    // Address of object (container id + object id)
    refs.Address Address                     = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "Address"];
    // FullHeaders can be set true for extended headers in the object
    bool FullHeaders                         = 2;
    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}
message HeadResponse {
    // Object without payload
    Object Object = 1;
}

message SearchRequest {
    // ContainerID for searching the object
    bytes ContainerID                        = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "CID"];
    // Query in the binary serialized format
    bytes Query                              = 2;
    // QueryVersion is a version of search query format
    uint32 QueryVersion                     = 3;
    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}

message SearchResponse {
    // Addresses of found objects
    repeated refs.Address Addresses = 1 [(gogoproto.nullable) = false];
}

message GetRangeRequest {
    // Address of object (container id + object id)
    refs.Address Address                     = 1 [(gogoproto.nullable) = false];
    // Ranges of object's payload to return
    repeated Range Ranges                    = 2 [(gogoproto.nullable) = false];
    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}

message GetRangeResponse {
    // Fragments of object's payload
    repeated bytes Fragments = 1;
}

message GetRangeHashRequest {
    // Address of object (container id + object id)
    refs.Address Address                     = 1 [(gogoproto.nullable) = false];
    // Ranges of object's payload to calculate homomorphic hash
    repeated Range Ranges                    = 2 [(gogoproto.nullable) = false];
    // Salt is used to XOR object's payload ranges before hashing, it can be nil
    bytes Salt                               = 3;
    // RequestMetaHeader contains information about request meta headers (should be embedded into message)
    service.RequestMetaHeader Meta           = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
    // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
    service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
}

message GetRangeHashResponse {
    // Hashes is a homomorphic hashes of all ranges
    repeated bytes Hashes = 1 [(gogoproto.customtype) = "Hash", (gogoproto.nullable) = false];
}