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  }