package object import ( "bytes" "context" "github.com/gogo/protobuf/proto" "github.com/nspcc-dev/neofs-api-go/internal" "github.com/nspcc-dev/neofs-api-go/refs" "github.com/nspcc-dev/neofs-api-go/session" ) type ( // Pred defines a predicate function that can check if passed header // satisfies predicate condition. It is used to find headers of // specific type. Pred = func(*Header) bool // Address is a type alias of object Address. Address = refs.Address // VerificationHeader is a type alias of session's verification header. VerificationHeader = session.VerificationHeader // PositionReader defines object reader that returns slice of bytes // for specified object and data range. PositionReader interface { PRead(ctx context.Context, addr refs.Address, rng Range) ([]byte, error) } headerType int ) const ( // ErrVerifyPayload is raised when payload checksum cannot be verified. ErrVerifyPayload = internal.Error("can't verify payload") // ErrVerifyHeader is raised when object integrity cannot be verified. ErrVerifyHeader = internal.Error("can't verify header") // ErrHeaderNotFound is raised when requested header not found. ErrHeaderNotFound = internal.Error("header not found") // ErrVerifySignature is raised when signature cannot be verified. ErrVerifySignature = internal.Error("can't verify signature") ) const ( _ headerType = iota // LinkHdr is a link header type. LinkHdr // RedirectHdr is a redirect header type. RedirectHdr // UserHdr is a user defined header type. UserHdr // TransformHdr is a transformation header type. TransformHdr // TombstoneHdr is a tombstone header type. TombstoneHdr // VerifyHdr is a verification header type. VerifyHdr // HomoHashHdr is a homomorphic hash header type. HomoHashHdr // PayloadChecksumHdr is a payload checksum header type. PayloadChecksumHdr // IntegrityHdr is a integrity header type. IntegrityHdr // StorageGroupHdr is a storage group header type. StorageGroupHdr // PublicKeyHdr is a public key header type. PublicKeyHdr ) var ( _ internal.Custom = (*Object)(nil) emptyObject = new(Object).Bytes() ) // Bytes returns marshaled object in a binary format. func (m Object) Bytes() []byte { data, _ := m.Marshal(); return data } // Empty checks if object does not contain any information. func (m Object) Empty() bool { return bytes.Equal(m.Bytes(), emptyObject) } // LastHeader returns last header of the specified type. Type must be // specified as a Pred function. func (m Object) LastHeader(f Pred) (int, *Header) { for i := len(m.Headers) - 1; i >= 0; i-- { if f != nil && f(&m.Headers[i]) { return i, &m.Headers[i] } } return -1, nil } // AddHeader adds passed header to the end of extended header list. func (m *Object) AddHeader(h *Header) { m.Headers = append(m.Headers, *h) } // SetPayload sets payload field and payload length in the system header. func (m *Object) SetPayload(payload []byte) { m.Payload = payload m.SystemHeader.PayloadLength = uint64(len(payload)) } // SetHeader replaces existing extended header or adds new one to the end of // extended header list. func (m *Object) SetHeader(h *Header) { // looking for the header of that type for i := range m.Headers { if m.Headers[i].typeOf(h.Value) { // if we found one - set it with new value and return m.Headers[i] = *h return } } // if we did not find one - add this header m.AddHeader(h) } func (m Header) typeOf(t isHeader_Value) (ok bool) { switch t.(type) { case *Header_Link: _, ok = m.Value.(*Header_Link) case *Header_Redirect: _, ok = m.Value.(*Header_Redirect) case *Header_UserHeader: _, ok = m.Value.(*Header_UserHeader) case *Header_Transform: _, ok = m.Value.(*Header_Transform) case *Header_Tombstone: _, ok = m.Value.(*Header_Tombstone) case *Header_Verify: _, ok = m.Value.(*Header_Verify) case *Header_HomoHash: _, ok = m.Value.(*Header_HomoHash) case *Header_PayloadChecksum: _, ok = m.Value.(*Header_PayloadChecksum) case *Header_Integrity: _, ok = m.Value.(*Header_Integrity) case *Header_StorageGroup: _, ok = m.Value.(*Header_StorageGroup) case *Header_PublicKey: _, ok = m.Value.(*Header_PublicKey) } return } // HeaderType returns predicate that check if extended header is a header // of specified type. func HeaderType(t headerType) Pred { switch t { case LinkHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_Link); return ok } case RedirectHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_Redirect); return ok } case UserHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_UserHeader); return ok } case TransformHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_Transform); return ok } case TombstoneHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_Tombstone); return ok } case VerifyHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_Verify); return ok } case HomoHashHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_HomoHash); return ok } case PayloadChecksumHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_PayloadChecksum); return ok } case IntegrityHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_Integrity); return ok } case StorageGroupHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_StorageGroup); return ok } case PublicKeyHdr: return func(h *Header) bool { _, ok := h.Value.(*Header_PublicKey); return ok } default: return nil } } // Copy creates full copy of the object. func (m *Object) Copy() (obj *Object) { obj = new(Object) m.CopyTo(obj) return } // CopyTo creates fills passed object with the data from the current object. // This function creates copies on every available data slice. func (m *Object) CopyTo(o *Object) { o.SystemHeader = m.SystemHeader o.Headers = make([]Header, len(m.Headers)) o.Payload = make([]byte, len(m.Payload)) for i := range m.Headers { switch v := m.Headers[i].Value.(type) { case *Header_Link: link := *v.Link o.Headers[i] = Header{ Value: &Header_Link{ Link: &link, }, } case *Header_HomoHash: o.Headers[i] = Header{ Value: &Header_HomoHash{ HomoHash: v.HomoHash, }, } default: o.Headers[i] = *proto.Clone(&m.Headers[i]).(*Header) } } copy(o.Payload, m.Payload) } // Address returns object's address. func (m Object) Address() *refs.Address { return &refs.Address{ ObjectID: m.SystemHeader.ID, CID: m.SystemHeader.CID, } }