git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/object.go (about) 1 package object 2 3 import ( 4 "errors" 5 "fmt" 6 "slices" 7 "strings" 8 9 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" 10 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" 11 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" 12 v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" 13 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" 14 cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" 15 frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" 16 oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" 17 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" 18 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" 19 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" 20 ) 21 22 // Object represents in-memory structure of the FrostFS object. 23 // Type is compatible with FrostFS API V2 protocol. 24 // 25 // Instance can be created depending on scenario: 26 // - InitCreation (an object to be placed in container); 27 // - New (blank instance, usually needed for decoding); 28 // - NewFromV2 (when working under FrostFS API V2 protocol). 29 type Object object.Object 30 31 // RequiredFields contains the minimum set of object data that must be set 32 // by the FrostFS user at the stage of creation. 33 type RequiredFields struct { 34 // Identifier of the FrostFS container associated with the object. 35 Container cid.ID 36 37 // Object owner's user ID in the FrostFS system. 38 Owner user.ID 39 } 40 41 // InitCreation initializes the object instance with minimum set of required fields. 42 // Object is expected (but not required) to be blank. Object must not be nil. 43 func InitCreation(dst *Object, rf RequiredFields) { 44 dst.SetContainerID(rf.Container) 45 dst.SetOwnerID(rf.Owner) 46 } 47 48 // NewFromV2 wraps v2 Object message to Object. 49 func NewFromV2(oV2 *object.Object) *Object { 50 return (*Object)(oV2) 51 } 52 53 // New creates and initializes blank Object. 54 // 55 // Works similar as NewFromV2(new(Object)). 56 func New() *Object { 57 return NewFromV2(new(object.Object)) 58 } 59 60 // ToV2 converts Object to v2 Object message. 61 func (o *Object) ToV2() *object.Object { 62 return (*object.Object)(o) 63 } 64 65 // MarshalHeaderJSON marshals object's header 66 // into JSON format. 67 func (o *Object) MarshalHeaderJSON() ([]byte, error) { 68 return (*object.Object)(o).GetHeader().MarshalJSON() 69 } 70 71 func (o *Object) setHeaderField(setter func(*object.Header)) { 72 obj := (*object.Object)(o) 73 h := obj.GetHeader() 74 75 if h == nil { 76 h = new(object.Header) 77 obj.SetHeader(h) 78 } 79 80 setter(h) 81 } 82 83 func (o *Object) setSplitFields(setter func(*object.SplitHeader)) { 84 o.setHeaderField(func(h *object.Header) { 85 split := h.GetSplit() 86 if split == nil { 87 split = new(object.SplitHeader) 88 h.SetSplit(split) 89 } 90 91 setter(split) 92 }) 93 } 94 95 // ID returns object identifier. 96 func (o *Object) ID() (v oid.ID, isSet bool) { 97 v2 := (*object.Object)(o) 98 if id := v2.GetObjectID(); id != nil { 99 _ = v.ReadFromV2(*v2.GetObjectID()) 100 isSet = true 101 } 102 103 return 104 } 105 106 // SetID sets object identifier. 107 func (o *Object) SetID(v oid.ID) { 108 var v2 refs.ObjectID 109 v.WriteToV2(&v2) 110 111 (*object.Object)(o). 112 SetObjectID(&v2) 113 } 114 115 // Signature returns signature of the object identifier. 116 func (o *Object) Signature() *frostfscrypto.Signature { 117 sigv2 := (*object.Object)(o).GetSignature() 118 if sigv2 == nil { 119 return nil 120 } 121 122 var sig frostfscrypto.Signature 123 _ = sig.ReadFromV2(*sigv2) // FIXME(@cthulhu-rider): #226 handle error 124 125 return &sig 126 } 127 128 // SetSignature sets signature of the object identifier. 129 func (o *Object) SetSignature(v *frostfscrypto.Signature) { 130 var sigv2 *refs.Signature 131 132 if v != nil { 133 sigv2 = new(refs.Signature) 134 135 v.WriteToV2(sigv2) 136 } 137 138 (*object.Object)(o).SetSignature(sigv2) 139 } 140 141 // Payload returns payload bytes. 142 func (o *Object) Payload() []byte { 143 return (*object.Object)(o).GetPayload() 144 } 145 146 // SetPayload sets payload bytes. 147 func (o *Object) SetPayload(v []byte) { 148 (*object.Object)(o).SetPayload(v) 149 } 150 151 // Version returns version of the object. 152 func (o *Object) Version() *version.Version { 153 var ver version.Version 154 if verV2 := (*object.Object)(o).GetHeader().GetVersion(); verV2 != nil { 155 _ = ver.ReadFromV2(*verV2) // FIXME(@cthulhu-rider): #226 handle error 156 } 157 return &ver 158 } 159 160 // SetVersion sets version of the object. 161 func (o *Object) SetVersion(v *version.Version) { 162 var verV2 refs.Version 163 v.WriteToV2(&verV2) 164 165 o.setHeaderField(func(h *object.Header) { 166 h.SetVersion(&verV2) 167 }) 168 } 169 170 // PayloadSize returns payload length of the object. 171 func (o *Object) PayloadSize() uint64 { 172 return (*object.Object)(o). 173 GetHeader(). 174 GetPayloadLength() 175 } 176 177 // SetPayloadSize sets payload length of the object. 178 func (o *Object) SetPayloadSize(v uint64) { 179 o.setHeaderField(func(h *object.Header) { 180 h.SetPayloadLength(v) 181 }) 182 } 183 184 // ContainerID returns identifier of the related container. 185 func (o *Object) ContainerID() (v cid.ID, isSet bool) { 186 v2 := (*object.Object)(o) 187 188 cidV2 := v2.GetHeader().GetContainerID() 189 if cidV2 != nil { 190 _ = v.ReadFromV2(*cidV2) 191 isSet = true 192 } 193 194 return 195 } 196 197 // SetContainerID sets identifier of the related container. 198 func (o *Object) SetContainerID(v cid.ID) { 199 var cidV2 refs.ContainerID 200 v.WriteToV2(&cidV2) 201 202 o.setHeaderField(func(h *object.Header) { 203 h.SetContainerID(&cidV2) 204 }) 205 } 206 207 // OwnerID returns identifier of the object owner and True. 208 func (o *Object) OwnerID() user.ID { 209 var id user.ID 210 211 m := (*object.Object)(o).GetHeader().GetOwnerID() 212 if m != nil { 213 _ = id.ReadFromV2(*m) 214 } 215 216 return id 217 } 218 219 // SetOwnerID sets identifier of the object owner. 220 func (o *Object) SetOwnerID(v user.ID) { 221 o.setHeaderField(func(h *object.Header) { 222 var m refs.OwnerID 223 v.WriteToV2(&m) 224 225 h.SetOwnerID(&m) 226 }) 227 } 228 229 // CreationEpoch returns epoch number in which object was created. 230 func (o *Object) CreationEpoch() uint64 { 231 return (*object.Object)(o). 232 GetHeader(). 233 GetCreationEpoch() 234 } 235 236 // SetCreationEpoch sets epoch number in which object was created. 237 func (o *Object) SetCreationEpoch(v uint64) { 238 o.setHeaderField(func(h *object.Header) { 239 h.SetCreationEpoch(v) 240 }) 241 } 242 243 // PayloadChecksum returns checksum of the object payload and 244 // bool that indicates checksum presence in the object. 245 // 246 // Zero Object does not have payload checksum. 247 // 248 // See also SetPayloadChecksum. 249 func (o *Object) PayloadChecksum() (checksum.Checksum, bool) { 250 var v checksum.Checksum 251 v2 := (*object.Object)(o) 252 253 if hash := v2.GetHeader().GetPayloadHash(); hash != nil { 254 _ = v.ReadFromV2(*hash) // FIXME(@cthulhu-rider): #226 handle error 255 return v, true 256 } 257 258 return v, false 259 } 260 261 // SetPayloadChecksum sets checksum of the object payload. 262 // 263 // See also PayloadChecksum. 264 func (o *Object) SetPayloadChecksum(v checksum.Checksum) { 265 var v2 refs.Checksum 266 v.WriteToV2(&v2) 267 268 o.setHeaderField(func(h *object.Header) { 269 h.SetPayloadHash(&v2) 270 }) 271 } 272 273 // PayloadHomomorphicHash returns homomorphic hash of the object 274 // payload and bool that indicates checksum presence in the object. 275 // 276 // Zero Object does not have payload homomorphic checksum. 277 // 278 // See also SetPayloadHomomorphicHash. 279 func (o *Object) PayloadHomomorphicHash() (checksum.Checksum, bool) { 280 var v checksum.Checksum 281 v2 := (*object.Object)(o) 282 283 if hash := v2.GetHeader().GetHomomorphicHash(); hash != nil { 284 _ = v.ReadFromV2(*hash) // FIXME(@cthulhu-rider): #226 handle error 285 return v, true 286 } 287 288 return v, false 289 } 290 291 // SetPayloadHomomorphicHash sets homomorphic hash of the object payload. 292 // 293 // See also PayloadHomomorphicHash. 294 func (o *Object) SetPayloadHomomorphicHash(v checksum.Checksum) { 295 var v2 refs.Checksum 296 v.WriteToV2(&v2) 297 298 o.setHeaderField(func(h *object.Header) { 299 h.SetHomomorphicHash(&v2) 300 }) 301 } 302 303 // Attributes returns object attributes. 304 func (o *Object) Attributes() []Attribute { 305 attrs := (*object.Object)(o). 306 GetHeader(). 307 GetAttributes() 308 309 res := make([]Attribute, len(attrs)) 310 311 for i := range attrs { 312 res[i] = *NewAttributeFromV2(&attrs[i]) 313 } 314 315 return res 316 } 317 318 // UserAttributes returns object user attributes. 319 func (o *Object) UserAttributes() []Attribute { 320 attrs := (*object.Object)(o). 321 GetHeader(). 322 GetAttributes() 323 324 res := make([]Attribute, 0, len(attrs)) 325 326 for _, attr := range attrs { 327 if !strings.HasPrefix(attr.GetKey(), container.SysAttributePrefix) { 328 res = append(res, *NewAttributeFromV2(&attr)) 329 } 330 } 331 332 return slices.Clip(res) 333 } 334 335 // SetAttributes sets object attributes. 336 func (o *Object) SetAttributes(v ...Attribute) { 337 attrs := make([]object.Attribute, len(v)) 338 339 for i := range v { 340 attrs[i] = *v[i].ToV2() 341 } 342 343 o.setHeaderField(func(h *object.Header) { 344 h.SetAttributes(attrs) 345 }) 346 } 347 348 // PreviousID returns identifier of the previous sibling object. 349 func (o *Object) PreviousID() (v oid.ID, isSet bool) { 350 v2 := (*object.Object)(o) 351 352 v2Prev := v2.GetHeader().GetSplit().GetPrevious() 353 if v2Prev != nil { 354 _ = v.ReadFromV2(*v2Prev) 355 isSet = true 356 } 357 358 return 359 } 360 361 // SetPreviousID sets identifier of the previous sibling object. 362 func (o *Object) SetPreviousID(v oid.ID) { 363 var v2 refs.ObjectID 364 v.WriteToV2(&v2) 365 366 o.setSplitFields(func(split *object.SplitHeader) { 367 split.SetPrevious(&v2) 368 }) 369 } 370 371 // Children return list of the identifiers of the child objects. 372 func (o *Object) Children() []oid.ID { 373 v2 := (*object.Object)(o) 374 ids := v2.GetHeader().GetSplit().GetChildren() 375 376 var ( 377 id oid.ID 378 res = make([]oid.ID, len(ids)) 379 ) 380 381 for i := range ids { 382 _ = id.ReadFromV2(ids[i]) 383 res[i] = id 384 } 385 386 return res 387 } 388 389 func (o *Object) GetECHeader() *ECHeader { 390 v2 := (*object.Object)(o).GetHeader().GetEC() 391 392 var ec ECHeader 393 _ = ec.ReadFromV2(v2) // Errors is checked on unmarshal. 394 return &ec 395 } 396 397 // SetChildren sets list of the identifiers of the child objects. 398 func (o *Object) SetChildren(v ...oid.ID) { 399 var ( 400 v2 refs.ObjectID 401 ids = make([]refs.ObjectID, len(v)) 402 ) 403 404 for i := range v { 405 v[i].WriteToV2(&v2) 406 ids[i] = v2 407 } 408 409 o.setSplitFields(func(split *object.SplitHeader) { 410 split.SetChildren(ids) 411 }) 412 } 413 414 // NotificationInfo groups information about object notification 415 // that can be written to object. 416 // 417 // Topic is an optional field. 418 type NotificationInfo struct { 419 ni object.NotificationInfo 420 } 421 422 // Epoch returns object notification tick 423 // epoch. 424 func (n NotificationInfo) Epoch() uint64 { 425 return n.ni.Epoch() 426 } 427 428 // SetEpoch sets object notification tick 429 // epoch. 430 func (n *NotificationInfo) SetEpoch(epoch uint64) { 431 n.ni.SetEpoch(epoch) 432 } 433 434 // Topic return optional object notification 435 // topic. 436 func (n NotificationInfo) Topic() string { 437 return n.ni.Topic() 438 } 439 440 // SetTopic sets optional object notification 441 // topic. 442 func (n *NotificationInfo) SetTopic(topic string) { 443 n.ni.SetTopic(topic) 444 } 445 446 // NotificationInfo returns notification info 447 // read from the object structure. 448 // Returns any error that appeared during notification 449 // information parsing. 450 func (o *Object) NotificationInfo() (*NotificationInfo, error) { 451 ni, err := object.GetNotificationInfo((*object.Object)(o)) 452 if err != nil { 453 return nil, err 454 } 455 456 return &NotificationInfo{ 457 ni: *ni, 458 }, nil 459 } 460 461 // SetNotification writes NotificationInfo to the object structure. 462 func (o *Object) SetNotification(ni NotificationInfo) { 463 object.WriteNotificationInfo((*object.Object)(o), ni.ni) 464 } 465 466 // SplitID return split identity of split object. If object is not split 467 // returns nil. 468 func (o *Object) SplitID() *SplitID { 469 return NewSplitIDFromV2( 470 (*object.Object)(o). 471 GetHeader(). 472 GetSplit(). 473 GetSplitID(), 474 ) 475 } 476 477 // SetSplitID sets split identifier for the split object. 478 func (o *Object) SetSplitID(id *SplitID) { 479 o.setSplitFields(func(split *object.SplitHeader) { 480 split.SetSplitID(id.ToV2()) 481 }) 482 } 483 484 // ParentID returns identifier of the parent object. 485 func (o *Object) ParentID() (v oid.ID, isSet bool) { 486 v2 := (*object.Object)(o) 487 488 v2Par := v2.GetHeader().GetSplit().GetParent() 489 if v2Par != nil { 490 _ = v.ReadFromV2(*v2Par) 491 isSet = true 492 } 493 494 return 495 } 496 497 // SetParentID sets identifier of the parent object. 498 func (o *Object) SetParentID(v oid.ID) { 499 var v2 refs.ObjectID 500 v.WriteToV2(&v2) 501 502 o.setSplitFields(func(split *object.SplitHeader) { 503 split.SetParent(&v2) 504 }) 505 } 506 507 // Parent returns parent object w/o payload. 508 func (o *Object) Parent() *Object { 509 h := (*object.Object)(o). 510 GetHeader(). 511 GetSplit() 512 513 parSig := h.GetParentSignature() 514 parHdr := h.GetParentHeader() 515 516 if parSig == nil && parHdr == nil { 517 return nil 518 } 519 520 oV2 := new(object.Object) 521 oV2.SetObjectID(h.GetParent()) 522 oV2.SetSignature(parSig) 523 oV2.SetHeader(parHdr) 524 525 return NewFromV2(oV2) 526 } 527 528 // SetParent sets parent object w/o payload. 529 func (o *Object) SetParent(v *Object) { 530 o.setSplitFields(func(split *object.SplitHeader) { 531 split.SetParent((*object.Object)(v).GetObjectID()) 532 split.SetParentSignature((*object.Object)(v).GetSignature()) 533 split.SetParentHeader((*object.Object)(v).GetHeader()) 534 }) 535 } 536 537 func (o *Object) initRelations() { 538 o.setHeaderField(func(h *object.Header) { 539 h.SetSplit(new(object.SplitHeader)) 540 }) 541 } 542 543 func (o *Object) resetRelations() { 544 o.setHeaderField(func(h *object.Header) { 545 h.SetSplit(nil) 546 }) 547 } 548 549 // SessionToken returns token of the session 550 // within which object was created. 551 func (o *Object) SessionToken() *session.Object { 552 tokv2 := (*object.Object)(o).GetHeader().GetSessionToken() 553 if tokv2 == nil { 554 return nil 555 } 556 557 var res session.Object 558 559 _ = res.ReadFromV2(*tokv2) 560 561 return &res 562 } 563 564 // SetSessionToken sets token of the session 565 // within which object was created. 566 func (o *Object) SetSessionToken(v *session.Object) { 567 o.setHeaderField(func(h *object.Header) { 568 var tokv2 *v2session.Token 569 570 if v != nil { 571 tokv2 = new(v2session.Token) 572 v.WriteToV2(tokv2) 573 } 574 575 h.SetSessionToken(tokv2) 576 }) 577 } 578 579 // Type returns type of the object. 580 func (o *Object) Type() Type { 581 return TypeFromV2( 582 (*object.Object)(o). 583 GetHeader(). 584 GetObjectType(), 585 ) 586 } 587 588 // SetType sets type of the object. 589 func (o *Object) SetType(v Type) { 590 o.setHeaderField(func(h *object.Header) { 591 h.SetObjectType(v.ToV2()) 592 }) 593 } 594 595 // CutPayload returns Object w/ empty payload. 596 // 597 // Changes of non-payload fields affect source object. 598 func (o *Object) CutPayload() *Object { 599 ov2 := new(object.Object) 600 *ov2 = *(*object.Object)(o) 601 ov2.SetPayload(nil) 602 ov2.SetMarshalData(nil) 603 604 return (*Object)(ov2) 605 } 606 607 func (o *Object) HasParent() bool { 608 return (*object.Object)(o). 609 GetHeader(). 610 GetSplit() != nil 611 } 612 613 // ResetRelations removes all fields of links with other objects. 614 func (o *Object) ResetRelations() { 615 o.resetRelations() 616 } 617 618 // InitRelations initializes relation field. 619 func (o *Object) InitRelations() { 620 o.initRelations() 621 } 622 623 // Marshal marshals object into a protobuf binary form. 624 func (o *Object) Marshal() ([]byte, error) { 625 return (*object.Object)(o).StableMarshal(nil), nil 626 } 627 628 // Unmarshal unmarshals protobuf binary representation of object. 629 func (o *Object) Unmarshal(data []byte) error { 630 err := (*object.Object)(o).Unmarshal(data) 631 if err != nil { 632 return err 633 } 634 635 return formatCheck((*object.Object)(o)) 636 } 637 638 // MarshalJSON encodes object to protobuf JSON format. 639 func (o *Object) MarshalJSON() ([]byte, error) { 640 return (*object.Object)(o).MarshalJSON() 641 } 642 643 // UnmarshalJSON decodes object from protobuf JSON format. 644 func (o *Object) UnmarshalJSON(data []byte) error { 645 err := (*object.Object)(o).UnmarshalJSON(data) 646 if err != nil { 647 return err 648 } 649 650 return formatCheck((*object.Object)(o)) 651 } 652 653 var ( 654 errOIDNotSet = errors.New("object ID is not set") 655 errCIDNotSet = errors.New("container ID is not set") 656 ) 657 658 func formatCheck(v2 *object.Object) error { 659 var ( 660 oID oid.ID 661 cID cid.ID 662 ) 663 664 oidV2 := v2.GetObjectID() 665 if oidV2 == nil { 666 return errOIDNotSet 667 } 668 669 err := oID.ReadFromV2(*oidV2) 670 if err != nil { 671 return fmt.Errorf("could not convert V2 object ID: %w", err) 672 } 673 674 cidV2 := v2.GetHeader().GetContainerID() 675 if cidV2 == nil { 676 return errCIDNotSet 677 } 678 679 err = cID.ReadFromV2(*cidV2) 680 if err != nil { 681 return fmt.Errorf("could not convert V2 container ID: %w", err) 682 } 683 684 if prev := v2.GetHeader().GetSplit().GetPrevious(); prev != nil { 685 err = oID.ReadFromV2(*prev) 686 if err != nil { 687 return fmt.Errorf("could not convert previous object ID: %w", err) 688 } 689 } 690 691 if parent := v2.GetHeader().GetSplit().GetParent(); parent != nil { 692 err = oID.ReadFromV2(*parent) 693 if err != nil { 694 return fmt.Errorf("could not convert parent object ID: %w", err) 695 } 696 } 697 698 return nil 699 }