github.com/TrueCloudLab/frostfs-api-go/v2@v2.0.0-20230228134343-196241c4e79a/object/attributes.go (about)

     1  package object
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  )
     8  
     9  // SysAttributePrefix is a prefix of key to system attribute.
    10  const SysAttributePrefix = "__NEOFS__"
    11  
    12  const (
    13  	// SysAttributeUploadID marks smaller parts of a split bigger object.
    14  	SysAttributeUploadID = SysAttributePrefix + "UPLOAD_ID"
    15  
    16  	// SysAttributeExpEpoch tells GC to delete object after that epoch.
    17  	SysAttributeExpEpoch = SysAttributePrefix + "EXPIRATION_EPOCH"
    18  
    19  	// SysAttributeTickEpoch defines what epoch must produce object
    20  	// notification.
    21  	SysAttributeTickEpoch = SysAttributePrefix + "TICK_EPOCH"
    22  
    23  	// SysAttributeTickTopic defines what topic object notification
    24  	// must be sent to.
    25  	SysAttributeTickTopic = SysAttributePrefix + "TICK_TOPIC"
    26  )
    27  
    28  // NotificationInfo groups information about object notification
    29  // that can be written to object.
    30  //
    31  // Topic is an optional field.
    32  type NotificationInfo struct {
    33  	epoch uint64
    34  	topic string
    35  }
    36  
    37  // Epoch returns object notification tick
    38  // epoch.
    39  func (n NotificationInfo) Epoch() uint64 {
    40  	return n.epoch
    41  }
    42  
    43  // SetEpoch sets object notification tick
    44  // epoch.
    45  func (n *NotificationInfo) SetEpoch(epoch uint64) {
    46  	n.epoch = epoch
    47  }
    48  
    49  // Topic return optional object notification
    50  // topic.
    51  func (n NotificationInfo) Topic() string {
    52  	return n.topic
    53  }
    54  
    55  // SetTopic sets optional object notification
    56  // topic.
    57  func (n *NotificationInfo) SetTopic(topic string) {
    58  	n.topic = topic
    59  }
    60  
    61  // WriteNotificationInfo writes NotificationInfo to the Object via attributes. Object must not be nil.
    62  //
    63  // Existing notification attributes are expected to be key-unique, otherwise undefined behavior.
    64  func WriteNotificationInfo(o *Object, ni NotificationInfo) {
    65  	h := o.GetHeader()
    66  	if h == nil {
    67  		h = new(Header)
    68  		o.SetHeader(h)
    69  	}
    70  
    71  	var (
    72  		attrs = h.GetAttributes()
    73  
    74  		epoch = strconv.FormatUint(ni.Epoch(), 10)
    75  		topic = ni.Topic()
    76  
    77  		changedEpoch bool
    78  		changedTopic bool
    79  		deleteIndex  = -1
    80  	)
    81  
    82  	for i := range attrs {
    83  		switch attrs[i].GetKey() {
    84  		case SysAttributeTickEpoch:
    85  			attrs[i].SetValue(epoch)
    86  			changedEpoch = true
    87  		case SysAttributeTickTopic:
    88  			changedTopic = true
    89  
    90  			if topic == "" {
    91  				deleteIndex = i
    92  				break
    93  			}
    94  
    95  			attrs[i].SetValue(topic)
    96  		}
    97  
    98  		if changedEpoch && changedTopic {
    99  			break
   100  		}
   101  	}
   102  
   103  	if deleteIndex != -1 {
   104  		// approach without allocation/waste
   105  		// coping works since the attributes
   106  		// order is not important
   107  		attrs[deleteIndex] = attrs[len(attrs)-1]
   108  		attrs = attrs[:len(attrs)-1]
   109  	}
   110  
   111  	if !changedEpoch {
   112  		index := len(attrs)
   113  		attrs = append(attrs, Attribute{})
   114  		attrs[index].SetKey(SysAttributeTickEpoch)
   115  		attrs[index].SetValue(epoch)
   116  	}
   117  
   118  	if !changedTopic && topic != "" {
   119  		index := len(attrs)
   120  		attrs = append(attrs, Attribute{})
   121  		attrs[index].SetKey(SysAttributeTickTopic)
   122  		attrs[index].SetValue(topic)
   123  	}
   124  
   125  	h.SetAttributes(attrs)
   126  }
   127  
   128  // ErrNotificationNotSet means that object does not have notification.
   129  var ErrNotificationNotSet = errors.New("notification for object is not set")
   130  
   131  // GetNotificationInfo looks for object notification attributes. Object must not be nil.
   132  // Returns ErrNotificationNotSet if no corresponding attributes
   133  // were found.
   134  //
   135  // Existing notification attributes are expected to be key-unique, otherwise undefined behavior.
   136  func GetNotificationInfo(o *Object) (*NotificationInfo, error) {
   137  	var (
   138  		foundEpoch bool
   139  		ni         = new(NotificationInfo)
   140  	)
   141  
   142  	for _, attr := range o.GetHeader().GetAttributes() {
   143  		switch key := attr.GetKey(); key {
   144  		case SysAttributeTickEpoch:
   145  			epoch, err := strconv.ParseUint(attr.GetValue(), 10, 64)
   146  			if err != nil {
   147  				return nil, fmt.Errorf("could not parse epoch: %w", err)
   148  			}
   149  
   150  			ni.SetEpoch(epoch)
   151  
   152  			foundEpoch = true
   153  		case SysAttributeTickTopic:
   154  			ni.SetTopic(attr.GetValue())
   155  		}
   156  	}
   157  
   158  	if !foundEpoch {
   159  		return nil, ErrNotificationNotSet
   160  	}
   161  
   162  	return ni, nil
   163  }