git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/client/object_delete.go (about) 1 package client 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "fmt" 7 8 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" 9 v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" 10 v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" 11 rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" 12 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" 13 v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" 14 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" 15 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" 16 apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" 17 cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" 18 oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" 19 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" 20 ) 21 22 // PrmObjectDelete groups parameters of ObjectDelete operation. 23 type PrmObjectDelete struct { 24 XHeaders []string 25 26 BearerToken *bearer.Token 27 28 Session *session.Object 29 30 ContainerID *cid.ID 31 32 ObjectID *oid.ID 33 34 Key *ecdsa.PrivateKey 35 } 36 37 // UseKey specifies private key to sign the requests. 38 // If key is not provided, then Client default key is used. 39 // 40 // Deprecated: Use PrmObjectDelete.Key instead. 41 func (prm *PrmObjectDelete) UseKey(key ecdsa.PrivateKey) { 42 prm.Key = &key 43 } 44 45 // ResObjectDelete groups resulting values of ObjectDelete operation. 46 type ResObjectDelete struct { 47 statusRes 48 49 tomb oid.ID 50 } 51 52 // Tombstone returns identifier of the created tombstone object. 53 func (x ResObjectDelete) Tombstone() oid.ID { 54 return x.tomb 55 } 56 57 func (prm *PrmObjectDelete) buildRequest(c *Client) (*v2object.DeleteRequest, error) { 58 if prm.ContainerID == nil { 59 return nil, errorMissingContainer 60 } 61 62 if prm.ObjectID == nil { 63 return nil, errorMissingObject 64 } 65 66 if len(prm.XHeaders)%2 != 0 { 67 return nil, errorInvalidXHeaders 68 } 69 70 meta := new(v2session.RequestMetaHeader) 71 writeXHeadersToMeta(prm.XHeaders, meta) 72 73 if prm.BearerToken != nil { 74 v2BearerToken := new(acl.BearerToken) 75 prm.BearerToken.WriteToV2(v2BearerToken) 76 meta.SetBearerToken(v2BearerToken) 77 } 78 79 if prm.Session != nil { 80 v2SessionToken := new(v2session.Token) 81 prm.Session.WriteToV2(v2SessionToken) 82 meta.SetSessionToken(v2SessionToken) 83 } 84 85 addr := new(v2refs.Address) 86 87 cnrV2 := new(v2refs.ContainerID) 88 prm.ContainerID.WriteToV2(cnrV2) 89 addr.SetContainerID(cnrV2) 90 91 objV2 := new(v2refs.ObjectID) 92 prm.ObjectID.WriteToV2(objV2) 93 addr.SetObjectID(objV2) 94 95 body := new(v2object.DeleteRequestBody) 96 body.SetAddress(addr) 97 98 req := new(v2object.DeleteRequest) 99 req.SetBody(body) 100 c.prepareRequest(req, meta) 101 102 return req, nil 103 } 104 105 // ObjectDelete marks an object for deletion from the container using FrostFS API protocol. 106 // As a marker, a special unit called a tombstone is placed in the container. 107 // It confirms the user's intent to delete the object, and is itself a container object. 108 // Explicit deletion is done asynchronously, and is generally not guaranteed. 109 // 110 // Returns a list of checksums in raw form: the format of hashes and their number 111 // is left for the caller to check. Client preserves the order of the server's response. 112 // 113 // Exactly one return value is non-nil. By default, server status is returned in res structure. 114 // Any client's internal or transport errors are returned as `error`, 115 // If PrmInit.DisableFrostFSFailuresResolution has been called, unsuccessful 116 // FrostFS status codes are included in the returned result structure, 117 // otherwise, are also returned as `error`. 118 // 119 // Returns an error if parameters are set incorrectly (see PrmObjectDelete docs). 120 // Context is required and must not be nil. It is used for network communication. 121 // 122 // Return statuses: 123 // - global (see Client docs) 124 // - *apistatus.ContainerNotFound; 125 // - *apistatus.ObjectAccessDenied; 126 // - *apistatus.ObjectLocked; 127 // - *apistatus.SessionTokenExpired. 128 func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObjectDelete, error) { 129 req, err := prm.buildRequest(c) 130 if err != nil { 131 return nil, err 132 } 133 134 key := c.prm.Key 135 if prm.Key != nil { 136 key = *prm.Key 137 } 138 139 err = signature.SignServiceMessage(&key, req) 140 if err != nil { 141 return nil, fmt.Errorf("sign request: %w", err) 142 } 143 144 resp, err := rpcapi.DeleteObject(&c.c, req, client.WithContext(ctx)) 145 if err != nil { 146 return nil, err 147 } 148 149 var res ResObjectDelete 150 res.st, err = c.processResponse(resp) 151 if err != nil || !apistatus.IsSuccessful(res.st) { 152 return &res, err 153 } 154 155 const fieldTombstone = "tombstone" 156 157 idTombV2 := resp.GetBody().GetTombstone().GetObjectID() 158 if idTombV2 == nil { 159 return nil, newErrMissingResponseField(fieldTombstone) 160 } 161 162 err = res.tomb.ReadFromV2(*idTombV2) 163 if err != nil { 164 return nil, newErrInvalidResponseField(fieldTombstone, err) 165 } 166 167 return &res, nil 168 }