diff --git a/object/service.proto b/object/service.proto index a92c42a..dc39c1c 100644 --- a/object/service.proto +++ b/object/service.proto @@ -283,6 +283,51 @@ service ObjectService { // - **TOKEN_EXPIRED** (4097, SECTION_SESSION): \ // provided session token has expired. rpc PutSingle(PutSingleRequest) returns (PutSingleResponse); + + // Patch the object. Request uses gRPC stream. First message must set + // the address of the object that is going to get patched. If the object's attributes + // are patched, then these attrubutes must be set only within the first stream message. + // + // If the patch request is performed by NOT the object's owner but if the actor has the permission + // to perform the patch, then `OwnerID` of the object is changed. In this case the object's owner + // loses the object's ownership after the patch request is successfully done. + // + // As objects are content-addressable the patching causes new object ID generation for the patched object. + // This object id is set witihn `PatchResponse`. But the object id may remain unchanged in such cases: + // 1. The chunk of the applying patch contains the same value as the object's payload within the same range; + // 2. The patch that reverts the changes applied by preceding patch; + // 3. The application of the same patches for the object a few times. + // + // Extended headers can change `Patch` behaviour: + // * [ __SYSTEM__NETMAP_EPOCH \ + // (`__NEOFS__NETMAP_EPOCH` is deprecated) \ + // Will use the requsted version of Network Map for object placement + // calculation. + // + // Please refer to detailed `XHeader` description. + // + // Statuses: + // - **OK** (0, SECTION_SUCCESS): \ + // object has been successfully patched and saved in the container; + // - Common failures (SECTION_FAILURE_COMMON); + // - **ACCESS_DENIED** (2048, SECTION_OBJECT): \ + // write access to the container is denied; + // - **OBJECT_NOT_FOUND** (2049, SECTION_OBJECT): \ + // object not found in container; + // - **OBJECT_ALREADY_REMOVED** (2052, SECTION_OBJECT): \ + // the requested object has been marked as deleted. + // - **OUT_OF_RANGE** (2053, SECTION_OBJECT): \ + // the requested range is out of bounds; + // - **CONTAINER_NOT_FOUND** (3072, SECTION_CONTAINER): \ + // object storage container not found; + // - **CONTAINER_ACCESS_DENIED** (3074, SECTION_CONTAINER): \ + // access to container is denied; + // - **TOKEN_NOT_FOUND** (4096, SECTION_SESSION): \ + // (for trusted object preparation) session private key does not exist or + // has been deleted; + // - **TOKEN_EXPIRED** (4097, SECTION_SESSION): \ + // provided session token has expired. + rpc Patch(stream PatchRequest) returns (PatchResponse); } // GET object request @@ -816,4 +861,70 @@ message PutSingleResponse { // authenticate the nodes of the message route and check the correctness of // transmission. neo.fs.v2.session.ResponseVerificationHeader verify_header = 3; -} \ No newline at end of file +} + +// Object PATCH request +message PatchRequest { + // PATCH request body + message Body { + // The address of the object that is requested to get patched. + neo.fs.v2.refs.Address address = 1; + + // New attributes for the object. See `replace_attributes` flag usage to define how + // new attributes should be set. + repeated neo.fs.v2.object.Header.Attribute new_attributes = 2; + + // If this flag is set, then the object's attributes will be entirely replaced by `new_attributes` list. + // The empty `new_attributes` list with `replace_attributes = true` just resets attributes list for the object. + // + // Default `false` value for this flag means the attributes will be just merged. If the incoming `new_attributes` + // list contains already existing key, then it just replaces it while merging the lists. + bool replace_attributes = 3; + + // The patch for the object's payload. + message Patch { + // The range of the source object for which the payload is replaced by the patch's chunk. + // If the range's `length = 0`, then the patch's chunk is just appended to the original payload + // starting from the `offest` without any replace. + Range source_range = 1; + + // The chunk that is being appended to or that replaces the original payload on the given range. + bytes chunk = 2; + } + + // The patch that is applied for the object. + Patch patch = 4; + } + + // Body for patch request message. + Body body = 1; + + // Carries request meta information. Header data is used only to regulate + // message transport and does not affect request execution. + neo.fs.v2.session.RequestMetaHeader meta_header = 2; + + // Carries request verification information. This header is used to + // authenticate the nodes of the message route and check the correctness of + // transmission. + neo.fs.v2.session.RequestVerificationHeader verify_header = 3; +} + +// Object PATCH response +message PatchResponse { + // PATCH response body + message Body { + // The object ID of the saved patched object. + neo.fs.v2.refs.ObjectID object_id = 1; + } + + // Body for patch response message. + Body body = 1; + + // Carries response meta information. Header data is used only to regulate + // message transport and does not affect request execution. + neo.fs.v2.session.ResponseMetaHeader meta_header = 2; + + // Carries response verification information. This header is used to authenticate + // the nodes of the message route and check the correctness of transmission. + neo.fs.v2.session.ResponseVerificationHeader verify_header = 3; +} diff --git a/proto-docs/object.md b/proto-docs/object.md index c141a60..f353b3f 100644 --- a/proto-docs/object.md +++ b/proto-docs/object.md @@ -30,6 +30,11 @@ - [HeadResponse](#neo.fs.v2.object.HeadResponse) - [HeadResponse.Body](#neo.fs.v2.object.HeadResponse.Body) - [HeaderWithSignature](#neo.fs.v2.object.HeaderWithSignature) + - [PatchRequest](#neo.fs.v2.object.PatchRequest) + - [PatchRequest.Body](#neo.fs.v2.object.PatchRequest.Body) + - [PatchRequest.Body.Patch](#neo.fs.v2.object.PatchRequest.Body.Patch) + - [PatchResponse](#neo.fs.v2.object.PatchResponse) + - [PatchResponse.Body](#neo.fs.v2.object.PatchResponse.Body) - [PutRequest](#neo.fs.v2.object.PutRequest) - [PutRequest.Body](#neo.fs.v2.object.PutRequest.Body) - [PutRequest.Body.Init](#neo.fs.v2.object.PutRequest.Body.Init) @@ -88,6 +93,7 @@ rpc Search(SearchRequest) returns (stream SearchResponse); rpc GetRange(GetRangeRequest) returns (stream GetRangeResponse); rpc GetRangeHash(GetRangeHashRequest) returns (GetRangeHashResponse); rpc PutSingle(PutSingleRequest) returns (PutSingleResponse); +rpc Patch(stream PatchRequest) returns (PatchResponse); ``` @@ -395,6 +401,55 @@ been deleted; | Name | Input | Output | | ---- | ----- | ------ | | PutSingle | [PutSingleRequest](#neo.fs.v2.object.PutSingleRequest) | [PutSingleResponse](#neo.fs.v2.object.PutSingleResponse) | +#### Method Patch + +Patch the object. Request uses gRPC stream. First message must set +the address of the object that is going to get patched. If the object's attributes +are patched, then these attrubutes must be set only within the first stream message. + +If the patch request is performed by NOT the object's owner but if the actor has the permission +to perform the patch, then `OwnerID` of the object is changed. In this case the object's owner +loses the object's ownership after the patch request is successfully done. + +As objects are content-addressable the patching causes new object ID generation for the patched object. +This object id is set witihn `PatchResponse`. But the object id may remain unchanged in such cases: +1. The chunk of the applying patch contains the same value as the object's payload within the same range; +2. The patch that reverts the changes applied by preceding patch; +3. The application of the same patches for the object a few times. + +Extended headers can change `Patch` behaviour: +* [ __SYSTEM__NETMAP_EPOCH \ + (`__NEOFS__NETMAP_EPOCH` is deprecated) \ + Will use the requsted version of Network Map for object placement + calculation. + +Please refer to detailed `XHeader` description. + +Statuses: +- **OK** (0, SECTION_SUCCESS): \ + object has been successfully patched and saved in the container; +- Common failures (SECTION_FAILURE_COMMON); +- **ACCESS_DENIED** (2048, SECTION_OBJECT): \ + write access to the container is denied; +- **OBJECT_NOT_FOUND** (2049, SECTION_OBJECT): \ + object not found in container; +- **OBJECT_ALREADY_REMOVED** (2052, SECTION_OBJECT): \ + the requested object has been marked as deleted. +- **OUT_OF_RANGE** (2053, SECTION_OBJECT): \ + the requested range is out of bounds; +- **CONTAINER_NOT_FOUND** (3072, SECTION_CONTAINER): \ + object storage container not found; +- **CONTAINER_ACCESS_DENIED** (3074, SECTION_CONTAINER): \ + access to container is denied; +- **TOKEN_NOT_FOUND** (4096, SECTION_SESSION): \ + (for trusted object preparation) session private key does not exist or + has been deleted; +- **TOKEN_EXPIRED** (4097, SECTION_SESSION): \ + provided session token has expired. + +| Name | Input | Output | +| ---- | ----- | ------ | +| Patch | [PatchRequest](#neo.fs.v2.object.PatchRequest) | [PatchResponse](#neo.fs.v2.object.PatchResponse) | @@ -691,6 +746,71 @@ following steps: | signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signed `ObjectID` to verify full header's authenticity | + + +### Message PatchRequest +Object PATCH request + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| body | [PatchRequest.Body](#neo.fs.v2.object.PatchRequest.Body) | | Body for patch request message. | +| meta_header | [neo.fs.v2.session.RequestMetaHeader](#neo.fs.v2.session.RequestMetaHeader) | | Carries request meta information. Header data is used only to regulate message transport and does not affect request execution. | +| verify_header | [neo.fs.v2.session.RequestVerificationHeader](#neo.fs.v2.session.RequestVerificationHeader) | | Carries request verification information. This header is used to authenticate the nodes of the message route and check the correctness of transmission. | + + + + +### Message PatchRequest.Body +PATCH request body + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| address | [neo.fs.v2.refs.Address](#neo.fs.v2.refs.Address) | | The address of the object that is requested to get patched. | +| new_attributes | [Header.Attribute](#neo.fs.v2.object.Header.Attribute) | repeated | New attributes for the object. See `replace_attributes` flag usage to define how new attributes should be set. | +| replace_attributes | [bool](#bool) | | If this flag is set, then the object's attributes will be entirely replaced by `new_attributes` list. The empty `new_attributes` list with `replace_attributes = true` just resets attributes list for the object. + +Default `false` value for this flag means the attributes will be just merged. If the incoming `new_attributes` list contains already existing key, then it just replaces it while merging the lists. | +| patch | [PatchRequest.Body.Patch](#neo.fs.v2.object.PatchRequest.Body.Patch) | | The patch that is applied for the object. | + + + + +### Message PatchRequest.Body.Patch +The patch for the object's payload. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| source_range | [Range](#neo.fs.v2.object.Range) | | The range of the source object for which the payload is replaced by the patch's chunk. If the range's `length = 0`, then the patch's chunk is just appended to the original payload starting from the `offest` without any replace. | +| chunk | [bytes](#bytes) | | The chunk that is being appended to or that replaces the original payload on the given range. | + + + + +### Message PatchResponse +Object PATCH response + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| body | [PatchResponse.Body](#neo.fs.v2.object.PatchResponse.Body) | | Body for patch response message. | +| meta_header | [neo.fs.v2.session.ResponseMetaHeader](#neo.fs.v2.session.ResponseMetaHeader) | | Carries response meta information. Header data is used only to regulate message transport and does not affect request execution. | +| verify_header | [neo.fs.v2.session.ResponseVerificationHeader](#neo.fs.v2.session.ResponseVerificationHeader) | | Carries response verification information. This header is used to authenticate the nodes of the message route and check the correctness of transmission. | + + + + +### Message PatchResponse.Body +PATCH response body + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| object_id | [neo.fs.v2.refs.ObjectID](#neo.fs.v2.refs.ObjectID) | | The object ID of the saved patched object. | + + ### Message PutRequest