package client import ( "context" "crypto/ecdsa" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" ) // defaultGRPCPayloadChunkLen default value for maxChunkLen. // See PrmObjectPutInit.SetGRPCPayloadChunkLen for details. const defaultGRPCPayloadChunkLen = 3 << 20 // PrmObjectPutInit groups parameters of ObjectPutInit operation. type PrmObjectPutInit struct { copyNum []uint32 key *ecdsa.PrivateKey meta v2session.RequestMetaHeader maxChunkLen int maxSize uint64 epochSource transformer.EpochSource withoutHomomorphicHash bool } // SetCopiesNumber sets number of object copies that is enough to consider put successful. func (x *PrmObjectPutInit) SetCopiesNumber(copiesNumber uint32) { x.copyNum = []uint32{copiesNumber} } // SetCopiesNumberByVectors sets ordered list of minimal required object copies numbers // per placement vector. List's length MUST equal container's placement vector number, // otherwise request will fail. func (x *PrmObjectPutInit) SetCopiesNumberByVectors(copiesNumbers []uint32) { x.copyNum = copiesNumbers } // SetGRPCPayloadChunkLen sets maximum chunk length value for gRPC Put request. // Maximum chunk length restricts maximum byte length of the chunk // transmitted in a single stream message. It depends on // server settings and other message fields. // If not specified or negative value set, default value of 3MiB will be used. func (x *PrmObjectPutInit) SetGRPCPayloadChunkLen(v int) { x.maxChunkLen = v } // ResObjectPut groups the final result values of ObjectPutInit operation. type ResObjectPut struct { statusRes obj oid.ID } // StoredObjectID returns identifier of the saved object. func (x ResObjectPut) StoredObjectID() oid.ID { return x.obj } // ObjectWriter is designed to write one object or // multiple parts of one object to FrostFS system. // // Must be initialized using Client.ObjectPutInit, any other // usage is unsafe. type ObjectWriter interface { // WriteHeader writes header of the object. Result means success. // Failure reason can be received via Close. WriteHeader(context.Context, object.Object) bool // WritePayloadChunk writes chunk of the object payload. Result means success. // Failure reason can be received via Close. WritePayloadChunk(context.Context, []byte) bool // Close ends writing the object and returns the result of the operation // along with the final results. Must be called after using the ObjectWriter. // // Exactly one return value is non-nil. By default, server status is returned in res structure. // Any client's internal or transport errors are returned as Go built-in error. // If Client is tuned to resolve FrostFS API statuses, then FrostFS failures // codes are returned as error. // // Return statuses: // - global (see Client docs); // - *apistatus.ContainerNotFound; // - *apistatus.ObjectAccessDenied; // - *apistatus.ObjectLocked; // - *apistatus.LockNonRegularObject; // - *apistatus.SessionTokenNotFound; // - *apistatus.SessionTokenExpired. Close(context.Context) (*ResObjectPut, error) } // UseKey specifies private key to sign the requests. // If key is not provided, then Client default key is used. func (x *PrmObjectPutInit) UseKey(key ecdsa.PrivateKey) { x.key = &key } // WithBearerToken attaches bearer token to be used for the operation. // Should be called once before any writing steps. func (x *PrmObjectPutInit) WithBearerToken(t bearer.Token) { var v2token acl.BearerToken t.WriteToV2(&v2token) x.meta.SetBearerToken(&v2token) } // WithinSession specifies session within which object should be stored. // Should be called once before any writing steps. func (x *PrmObjectPutInit) WithinSession(t session.Object) { var tv2 v2session.Token t.WriteToV2(&tv2) x.meta.SetSessionToken(&tv2) } // MarkLocal tells the server to execute the operation locally. func (x *PrmObjectPutInit) MarkLocal() { x.meta.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 *PrmObjectPutInit) WithXHeaders(hs ...string) { writeXHeadersToMeta(hs, &x.meta) } // WithObjectMaxSize specifies max object size value and use it during object splitting. // When specified, start writing to the stream only after the object is formed. // Continue processing the input only when the previous formed object has been successfully written. func (x *PrmObjectPutInit) WithObjectMaxSize(maxSize uint64) { x.maxSize = maxSize } // WithoutHomomorphicHash if set to true do not use Tillich-ZĂ©mor hash for payload. func (x *PrmObjectPutInit) WithoutHomomorphicHash(v bool) { x.withoutHomomorphicHash = v } // WithEpochSource specifies epoch for object when split it on client side. func (x *PrmObjectPutInit) WithEpochSource(es transformer.EpochSource) { x.epochSource = es } // ObjectPutInit initiates writing an object through a remote server using FrostFS API protocol. // // The call only opens the transmission channel, explicit recording is done using the ObjectWriter. // Exactly one return value is non-nil. Resulting writer must be finally closed. // // Returns an error if parameters are set incorrectly. // Context is required and must not be nil. It is used for network communication. func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (ObjectWriter, error) { if prm.maxSize > 0 { return c.objectPutInitTransformer(prm) } return c.objectPutInitRaw(ctx, prm) }