2021-11-16 18:17:25 +00:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
2023-02-27 07:53:27 +00:00
|
|
|
"errors"
|
2021-11-16 18:17:25 +00:00
|
|
|
"fmt"
|
|
|
|
|
2024-10-07 14:20:25 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
|
|
|
v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature"
|
2023-03-07 11:20:03 +00:00
|
|
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
|
2021-11-16 18:17:25 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// structure is embedded to all resulting types in order to inherit status-related methods.
|
|
|
|
type statusRes struct {
|
|
|
|
st apistatus.Status
|
|
|
|
}
|
|
|
|
|
|
|
|
// Status returns server's status return.
|
|
|
|
//
|
|
|
|
// Use apistatus package functionality to handle the status.
|
|
|
|
func (x statusRes) Status() apistatus.Status {
|
|
|
|
return x.st
|
|
|
|
}
|
|
|
|
|
2022-08-23 17:51:05 +00:00
|
|
|
func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
|
|
|
|
if len(xHeaders) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-08-28 08:07:18 +00:00
|
|
|
// TODO (aarifullin): remove the panic when all client parameters will check XHeaders
|
|
|
|
// within buildRequest invocation.
|
2022-08-26 10:20:30 +00:00
|
|
|
if len(xHeaders)%2 != 0 {
|
|
|
|
panic("slice of X-Headers with odd length")
|
|
|
|
}
|
|
|
|
|
2022-08-23 17:51:05 +00:00
|
|
|
hs := make([]v2session.XHeader, len(xHeaders)/2)
|
|
|
|
for i := 0; i < len(xHeaders); i += 2 {
|
|
|
|
hs[i].SetKey(xHeaders[i])
|
|
|
|
hs[i].SetValue(xHeaders[i+1])
|
|
|
|
}
|
|
|
|
|
|
|
|
h.SetXHeaders(hs)
|
|
|
|
}
|
|
|
|
|
2023-02-27 07:53:27 +00:00
|
|
|
// error messages.
|
|
|
|
var (
|
2024-07-26 11:12:48 +00:00
|
|
|
errorMissingContainer = errors.New("missing container")
|
|
|
|
errorMissingObject = errors.New("missing object")
|
|
|
|
errorAccountNotSet = errors.New("account not set")
|
|
|
|
errorServerAddrUnset = errors.New("server address is unset or empty")
|
|
|
|
errorZeroRangeLength = errors.New("zero range length")
|
|
|
|
errorMissingRanges = errors.New("missing ranges")
|
|
|
|
errorInvalidXHeaders = errors.New("xheaders must be presented only as key-value pairs")
|
2021-12-02 12:21:54 +00:00
|
|
|
)
|
|
|
|
|
2022-08-23 17:51:05 +00:00
|
|
|
type request interface {
|
|
|
|
GetMetaHeader() *v2session.RequestMetaHeader
|
|
|
|
SetMetaHeader(*v2session.RequestMetaHeader)
|
|
|
|
SetVerificationHeader(*v2session.RequestVerificationHeader)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) prepareRequest(req request, meta *v2session.RequestMetaHeader) {
|
|
|
|
ttl := meta.GetTTL()
|
|
|
|
if ttl == 0 {
|
|
|
|
ttl = 2
|
|
|
|
}
|
|
|
|
|
|
|
|
verV2 := meta.GetVersion()
|
|
|
|
if verV2 == nil {
|
|
|
|
verV2 = new(refs.Version)
|
|
|
|
version.Current().WriteToV2(verV2)
|
|
|
|
}
|
|
|
|
|
|
|
|
meta.SetTTL(ttl)
|
|
|
|
meta.SetVersion(verV2)
|
2023-11-13 12:18:07 +00:00
|
|
|
meta.SetNetworkMagic(c.prm.NetMagic)
|
2022-08-23 17:51:05 +00:00
|
|
|
|
|
|
|
req.SetMetaHeader(meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// processResponse verifies response signature and converts status to an error if needed.
|
|
|
|
func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) {
|
2023-11-13 12:18:07 +00:00
|
|
|
if c.prm.ResponseInfoCallback != nil {
|
2023-04-13 05:49:05 +00:00
|
|
|
rmi := ResponseMetaInfo{
|
|
|
|
key: resp.GetVerificationHeader().GetBodySignature().GetKey(),
|
|
|
|
epoch: resp.GetMetaHeader().GetEpoch(),
|
|
|
|
}
|
2023-11-13 12:18:07 +00:00
|
|
|
if err := c.prm.ResponseInfoCallback(rmi); err != nil {
|
2023-04-13 05:49:05 +00:00
|
|
|
return nil, fmt.Errorf("response callback error: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-23 17:51:05 +00:00
|
|
|
err := signature.VerifyServiceMessage(resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid response signature: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
st := apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus())
|
2023-11-13 12:18:07 +00:00
|
|
|
if !c.prm.DisableFrostFSErrorResolution {
|
2022-08-23 17:51:05 +00:00
|
|
|
return st, apistatus.ErrFromStatus(st)
|
|
|
|
}
|
|
|
|
return st, nil
|
|
|
|
}
|
|
|
|
|
2024-10-07 14:20:25 +00:00
|
|
|
// ExecRaw executes f with underlying sdk-go/api/rpc/client.Client
|
2022-03-07 11:39:49 +00:00
|
|
|
// instance. Communicate over the Protocol Buffers protocol in a more flexible way:
|
2022-12-29 10:46:18 +00:00
|
|
|
// most often used to transmit data over a fixed version of the FrostFS protocol, as well
|
2022-03-07 11:39:49 +00:00
|
|
|
// as to support custom services.
|
|
|
|
//
|
|
|
|
// The f must not manipulate the client connection passed into it.
|
|
|
|
//
|
|
|
|
// Like all other operations, must be called after connecting to the server and
|
|
|
|
// before closing the connection.
|
|
|
|
//
|
|
|
|
// See also Dial and Close.
|
2024-10-07 14:20:25 +00:00
|
|
|
// See also git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client package docs.
|
2022-03-07 11:39:49 +00:00
|
|
|
func (c *Client) ExecRaw(f func(client *client.Client) error) error {
|
|
|
|
return f(&c.c)
|
2021-12-02 12:21:54 +00:00
|
|
|
}
|