diff --git a/client/accounting.go b/client/accounting.go index ccd74f1c..a4cffc5a 100644 --- a/client/accounting.go +++ b/client/accounting.go @@ -12,6 +12,8 @@ import ( // PrmBalanceGet groups parameters of BalanceGet operation. type PrmBalanceGet struct { + prmCommonMeta + ownerSet bool ownerID owner.ID } @@ -82,6 +84,7 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { diff --git a/client/common.go b/client/common.go index 30cccf36..f5d454f3 100644 --- a/client/common.go +++ b/client/common.go @@ -50,6 +50,40 @@ func (x prmSession) writeToMetaHeader(meta *v2session.RequestMetaHeader) { } } +// groups meta parameters shared between all Client operations. +type prmCommonMeta struct { + // NeoFS request X-Headers + xHeaders []string +} + +// WithXHeaders specifies list of extended headers (string key-value pairs) +// to be attached to the request. Must have an even length. +// +// Slice must not be mutated until the operation completes. +func (x *prmCommonMeta) WithXHeaders(hs ...string) { + if len(hs)%2 != 0 { + panic("slice of X-Headers with odd length") + } + + x.xHeaders = hs +} + +func (x prmCommonMeta) writeToMetaHeader(h *v2session.RequestMetaHeader) { + if len(x.xHeaders) > 0 { + hs := make([]*v2session.XHeader, 0, len(x.xHeaders)/2) + + for i := 0; i < len(x.xHeaders); i += 2 { + var h v2session.XHeader + h.SetKey(x.xHeaders[i]) + h.SetValue(x.xHeaders[i+1]) + + hs = append(hs, &h) + } + + h.SetXHeaders(hs) + } +} + // panic messages. const ( panicMsgMissingContext = "missing context" @@ -82,6 +116,9 @@ type contextCall struct { // NeoFS network magic netMagic uint64 + // Meta parameters + meta prmCommonMeta + // ================================================== // custom call parameters @@ -128,6 +165,8 @@ func (x contextCall) prepareRequest() { } meta.SetNetworkMagic(x.netMagic) + + x.meta.writeToMetaHeader(meta) } // prepares, signs and writes the request. Result means success. diff --git a/client/container.go b/client/container.go index 45f1e5c2..b64979fc 100644 --- a/client/container.go +++ b/client/container.go @@ -19,6 +19,8 @@ import ( // PrmContainerPut groups parameters of ContainerPut operation. type PrmContainerPut struct { + prmCommonMeta + cnrSet bool cnr container.Container } @@ -96,6 +98,7 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon // form meta header var meta v2session.RequestMetaHeader meta.SetSessionToken(prm.cnr.SessionToken().ToV2()) + prm.prmCommonMeta.writeToMetaHeader(&meta) // form request var req v2container.PutRequest @@ -131,6 +134,8 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon // PrmContainerGet groups parameters of ContainerGet operation. type PrmContainerGet struct { + prmCommonMeta + idSet bool id cid.ID } @@ -199,6 +204,7 @@ func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResCon ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { @@ -232,6 +238,8 @@ func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResCon // PrmContainerList groups parameters of ContainerList operation. type PrmContainerList struct { + prmCommonMeta + ownerSet bool ownerID owner.ID } @@ -302,6 +310,7 @@ func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResC ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { @@ -329,6 +338,7 @@ func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResC // PrmContainerDelete groups parameters of ContainerDelete operation. type PrmContainerDelete struct { + prmCommonMeta prmSession idSet bool @@ -408,6 +418,7 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (* var meta v2session.RequestMetaHeader prm.prmSession.writeToMetaHeader(&meta) + prm.prmCommonMeta.writeToMetaHeader(&meta) // form request var req v2container.DeleteRequest @@ -439,6 +450,8 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (* // PrmContainerEACL groups parameters of ContainerEACL operation. type PrmContainerEACL struct { + prmCommonMeta + idSet bool id cid.ID } @@ -508,6 +521,7 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { @@ -541,6 +555,8 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC // PrmContainerSetEACL groups parameters of ContainerSetEACL operation. type PrmContainerSetEACL struct { + prmCommonMeta + tableSet bool table eacl.Table } @@ -601,6 +617,7 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) // form meta header var meta v2session.RequestMetaHeader meta.SetSessionToken(prm.table.SessionToken().ToV2()) + prm.prmCommonMeta.writeToMetaHeader(&meta) // form request var req v2container.SetExtendedACLRequest @@ -632,6 +649,8 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) // PrmAnnounceSpace groups parameters of ContainerAnnounceUsedSpace operation. type PrmAnnounceSpace struct { + prmCommonMeta + announcements []container.UsedSpaceAnnouncement } @@ -698,6 +717,7 @@ func (c *Client) ContainerAnnounceUsedSpace(ctx context.Context, prm PrmAnnounce ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { diff --git a/client/netmap.go b/client/netmap.go index f0f4dd40..58c784f1 100644 --- a/client/netmap.go +++ b/client/netmap.go @@ -11,10 +11,9 @@ import ( ) // PrmEndpointInfo groups parameters of EndpointInfo operation. -// -// At the moment the operation is not parameterized, however, -// the structure is still declared for backward compatibility. -type PrmEndpointInfo struct{} +type PrmEndpointInfo struct { + prmCommonMeta +} // ResEndpointInfo group resulting values of EndpointInfo operation. type ResEndpointInfo struct { @@ -64,7 +63,7 @@ func (x *ResEndpointInfo) setNodeInfo(info *netmap.NodeInfo) { // // Return statuses: // - global (see Client docs). -func (c *Client) EndpointInfo(ctx context.Context, _ PrmEndpointInfo) (*ResEndpointInfo, error) { +func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEndpointInfo, error) { // check context if ctx == nil { panic(panicMsgMissingContext) @@ -81,6 +80,7 @@ func (c *Client) EndpointInfo(ctx context.Context, _ PrmEndpointInfo) (*ResEndpo ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { @@ -104,10 +104,9 @@ func (c *Client) EndpointInfo(ctx context.Context, _ PrmEndpointInfo) (*ResEndpo } // PrmNetworkInfo groups parameters of NetworkInfo operation. -// -// At the moment the operation is not parameterized, however, -// the structure is still declared for backward compatibility. -type PrmNetworkInfo struct{} +type PrmNetworkInfo struct { + prmCommonMeta +} // ResNetworkInfo groups resulting values of NetworkInfo operation. type ResNetworkInfo struct { @@ -142,7 +141,7 @@ func (x *ResNetworkInfo) setInfo(info *netmap.NetworkInfo) { // // Return statuses: // - global (see Client docs). -func (c *Client) NetworkInfo(ctx context.Context, _ PrmNetworkInfo) (*ResNetworkInfo, error) { +func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetworkInfo, error) { // check context if ctx == nil { panic(panicMsgMissingContext) @@ -159,6 +158,7 @@ func (c *Client) NetworkInfo(ctx context.Context, _ PrmNetworkInfo) (*ResNetwork ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { diff --git a/client/object_delete.go b/client/object_delete.go index 407822b0..d89d2e7e 100644 --- a/client/object_delete.go +++ b/client/object_delete.go @@ -65,6 +65,18 @@ func (x *PrmObjectDelete) UseKey(key ecdsa.PrivateKey) { x.key = key } +// WithXHeaders specifies list of extended headers (string key-value pairs) +// to be attached to the request. Must have an even length. +// +// Slice must not be mutated until the operation completes. +func (x *PrmObjectDelete) WithXHeaders(hs ...string) { + if len(hs)%2 != 0 { + panic("slice of X-Headers with odd length") + } + + prmCommonMeta{xHeaders: hs}.writeToMetaHeader(&x.meta) +} + // ResObjectDelete groups resulting values of ObjectDelete operation. type ResObjectDelete struct { statusRes diff --git a/client/object_get.go b/client/object_get.go index 3628b94c..fbd8c996 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -22,6 +22,8 @@ import ( // shared parameters of GET/HEAD/RANGE. type prmObjectRead struct { + prmCommonMeta + raw bool local bool @@ -39,6 +41,22 @@ type prmObjectRead struct { obj oid.ID } +func (x prmObjectRead) writeToMetaHeader(h *v2session.RequestMetaHeader) { + if x.local { + h.SetTTL(1) + } + + if x.bearerSet { + h.SetBearerToken(x.bearer.ToV2()) + } + + if x.sessionSet { + h.SetSessionToken(x.session.ToV2()) + } + + x.prmCommonMeta.writeToMetaHeader(h) +} + // MarkRaw marks an intent to read physically stored object. func (x *prmObjectRead) MarkRaw() { x.raw = true @@ -311,17 +329,7 @@ func (c *Client) ObjectGetInit(ctx context.Context, prm PrmObjectGet) (*ObjectRe // form meta header var meta v2session.RequestMetaHeader - if prm.local { - meta.SetTTL(1) - } - - if prm.bearerSet { - meta.SetBearerToken(prm.bearer.ToV2()) - } - - if prm.sessionSet { - meta.SetSessionToken(prm.session.ToV2()) - } + prm.prmObjectRead.writeToMetaHeader(&meta) // form request var req v2object.GetRequest @@ -490,17 +498,7 @@ func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectH // form meta header var meta v2session.RequestMetaHeader - if prm.local { - meta.SetTTL(1) - } - - if prm.bearerSet { - meta.SetBearerToken(prm.bearer.ToV2()) - } - - if prm.sessionSet { - meta.SetSessionToken(prm.session.ToV2()) - } + prm.prmObjectRead.writeToMetaHeader(&meta) // form request var req v2object.HeadRequest @@ -772,17 +770,7 @@ func (c *Client) ObjectRangeInit(ctx context.Context, prm PrmObjectRange) (*Obje // form meta header var meta v2session.RequestMetaHeader - if prm.local { - meta.SetTTL(1) - } - - if prm.bearerSet { - meta.SetBearerToken(prm.bearer.ToV2()) - } - - if prm.sessionSet { - meta.SetSessionToken(prm.session.ToV2()) - } + prm.prmObjectRead.writeToMetaHeader(&meta) // form request var req v2object.GetRangeRequest diff --git a/client/object_hash.go b/client/object_hash.go index 347f0fcd..b764505d 100644 --- a/client/object_hash.go +++ b/client/object_hash.go @@ -97,6 +97,18 @@ func (x *PrmObjectHash) UseSalt(salt []byte) { x.body.SetSalt(salt) } +// WithXHeaders specifies list of extended headers (string key-value pairs) +// to be attached to the request. Must have an even length. +// +// Slice must not be mutated until the operation completes. +func (x *PrmObjectHash) WithXHeaders(hs ...string) { + if len(hs)%2 != 0 { + panic("slice of X-Headers with odd length") + } + + prmCommonMeta{xHeaders: hs}.writeToMetaHeader(&x.meta) +} + // ResObjectHash groups resulting values of ObjectHash operation. type ResObjectHash struct { statusRes diff --git a/client/object_put.go b/client/object_put.go index 09d892f3..8daf8a5d 100644 --- a/client/object_put.go +++ b/client/object_put.go @@ -84,6 +84,18 @@ func (x *ObjectWriter) MarkLocal() { x.metaHdr.SetTTL(1) } +// WithXHeaders specifies list of extended headers (string key-value pairs) +// to be attached to the request. Must have an even length. +// +// Slice must not be mutated until the operation completes. +func (x *ObjectWriter) WithXHeaders(hs ...string) { + if len(hs)%2 != 0 { + panic("slice of X-Headers with odd length") + } + + prmCommonMeta{xHeaders: hs}.writeToMetaHeader(&x.metaHdr) +} + // WriteHeader writes header of the object. Result means success. // Failure reason can be received via Close. func (x *ObjectWriter) WriteHeader(hdr object.Object) bool { diff --git a/client/object_search.go b/client/object_search.go index a67976b0..42236c60 100644 --- a/client/object_search.go +++ b/client/object_search.go @@ -22,6 +22,8 @@ import ( // PrmObjectSearch groups parameters of ObjectSearch operation. type PrmObjectSearch struct { + prmCommonMeta + local bool sessionSet bool @@ -262,6 +264,8 @@ func (c *Client) ObjectSearchInit(ctx context.Context, prm PrmObjectSearch) (*Ob meta.SetSessionToken(prm.session.ToV2()) } + prm.prmCommonMeta.writeToMetaHeader(&meta) + // form request var req v2object.SearchRequest diff --git a/client/reputation.go b/client/reputation.go index 3b2ed932..d601362f 100644 --- a/client/reputation.go +++ b/client/reputation.go @@ -11,6 +11,8 @@ import ( // PrmAnnounceLocalTrust groups parameters of AnnounceLocalTrust operation. type PrmAnnounceLocalTrust struct { + prmCommonMeta + epoch uint64 trusts []reputation.Trust @@ -84,6 +86,7 @@ func (c *Client) AnnounceLocalTrust(ctx context.Context, prm PrmAnnounceLocalTru ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { @@ -100,6 +103,8 @@ func (c *Client) AnnounceLocalTrust(ctx context.Context, prm PrmAnnounceLocalTru // PrmAnnounceIntermediateTrust groups parameters of AnnounceIntermediateTrust operation. type PrmAnnounceIntermediateTrust struct { + prmCommonMeta + epoch uint64 iter uint32 @@ -176,6 +181,7 @@ func (c *Client) AnnounceIntermediateTrust(ctx context.Context, prm PrmAnnounceI ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) { diff --git a/client/session.go b/client/session.go index db4afed7..75f0b9d8 100644 --- a/client/session.go +++ b/client/session.go @@ -11,6 +11,8 @@ import ( // PrmSessionCreate groups parameters of SessionCreate operation. type PrmSessionCreate struct { + prmCommonMeta + exp uint64 } @@ -89,6 +91,7 @@ func (c *Client) SessionCreate(ctx context.Context, prm PrmSessionCreate) (*ResS ) c.initCallContext(&cc) + cc.meta = prm.prmCommonMeta cc.req = &req cc.statusRes = &res cc.call = func() (responseV2, error) {