github.com/amp-space/amp-sdk-go@v0.7.6/amp/msg.go (about)

     1  package amp
     2  
     3  import (
     4  	"encoding/binary"
     5  	"sync"
     6  )
     7  
     8  // TxDataStore is a message packet sent to / from a client.
     9  // It is leads with a fixed-size header (TxHeader_Size) followed by a variable-size body.
    10  type TxDataStore []byte
    11  
    12  func (tx TxDataStore) GetTxTotalLen() int {
    13  	if tx[TxHeader_OpOfs] != byte(TxHeader_OpRecvTx) {
    14  		return 0
    15  	}
    16  	bodySz := int(binary.BigEndian.Uint32(tx[3:7]))
    17  	return bodySz
    18  }
    19  
    20  func (tx TxDataStore) InitHeader(bodyLen int) {
    21  	tx[0] = 0
    22  	tx[1] = 0
    23  	tx[2] = 0
    24  	txLen := bodyLen + int(TxHeader_Size)
    25  	binary.BigEndian.PutUint32(tx[3:7], uint32(txLen))
    26  	tx[TxHeader_OpOfs] = byte(TxHeader_OpRecvTx)
    27  }
    28  
    29  ///////////////////////// host -> client /////////////////////////
    30  
    31  func (msg *Msg) MarshalToTxBuffer(txBuf []byte) error {
    32  	n, err := msg.MarshalToSizedBuffer(txBuf[TxHeader_Size:])
    33  	if err != nil {
    34  		return err
    35  	}
    36  	TxDataStore(txBuf).InitHeader(n)
    37  	return nil
    38  }
    39  
    40  // MsgBatch is an ordered list os Msgs
    41  // See NewMsgBatch()
    42  type MsgBatch struct {
    43  	Msgs []*Msg
    44  }
    45  
    46  /*
    47  var gMsgBatchPool = sync.Pool{
    48  	New: func() interface{} {
    49  		return &MsgBatch{
    50  			Msgs: make([]*Msg, 0, 16),
    51  		}
    52  	},
    53  }
    54  
    55  func NewMsgBatch() *MsgBatch {
    56  	return gMsgBatchPool.Get().(*MsgBatch)
    57  }
    58  
    59  func (batch *MsgBatch) Reset(count int) []*Msg {
    60  	if count > cap(batch.Msgs) {
    61  		msgs := make([]*Msg, count)
    62  		copy(msgs, batch.Msgs)
    63  		batch.Msgs = msgs
    64  	} else {
    65  		batch.Msgs = batch.Msgs[:count]
    66  	}
    67  
    68  	// Alloc or init  each msg
    69  	for i, msg := range batch.Msgs {
    70  		if msg == nil {
    71  			batch.Msgs[i] = NewMsg()
    72  		} else {
    73  			msg.Init()
    74  		}
    75  	}
    76  
    77  	return batch.Msgs
    78  }
    79  
    80  func (batch *MsgBatch) AddNew(count int) []*Msg {
    81  	N := len(batch.Msgs)
    82  	for i := 0; i < count; i++ {
    83  		batch.Msgs = append(batch.Msgs, NewMsg())
    84  	}
    85  	return batch.Msgs[N:]
    86  }
    87  
    88  func (batch *MsgBatch) AddMsgs(msgs []*Msg) {
    89  	batch.Msgs = append(batch.Msgs, msgs...)
    90  }
    91  
    92  func (batch *MsgBatch) AddMsg() *Msg {
    93  	m := NewMsg()
    94  	batch.Msgs = append(batch.Msgs, m)
    95  	return m
    96  }
    97  
    98  func (batch *MsgBatch) Reclaim() {
    99  	for i, msg := range batch.Msgs {
   100  		msg.Reclaim()
   101  		batch.Msgs[i] = nil
   102  	}
   103  	batch.Msgs = batch.Msgs[:0]
   104  	gMsgBatchPool.Put(batch)
   105  }
   106  
   107  func (batch *MsgBatch) PushCopyToClient(dst PinContext) bool {
   108  	for _, src := range batch.Msgs {
   109  		msg := CopyMsg(src)
   110  		if !dst.PushUpdate(msg) {
   111  			return false
   112  		}
   113  	}
   114  	return true
   115  }
   116  */
   117  
   118  func NewMsg() *Msg {
   119  	msg := gMsgPool.Get().(*Msg)
   120  	return msg
   121  }
   122  
   123  /*
   124  	func CopyMsg(src *Msg) *Msg {
   125  		msg := NewMsg()
   126  
   127  		if src != nil {
   128  			valBuf := append(msg.ValBuf[:0], src.ValBuf...)
   129  			*msg = *src
   130  			msg.ValBuf = valBuf
   131  
   132  		}
   133  		return msg
   134  	}
   135  */
   136  func (msg *Msg) Init() {
   137  	*msg = Msg{
   138  		CellTxs: msg.CellTxs[:0],
   139  	}
   140  }
   141  
   142  func (msg *Msg) Reclaim() {
   143  	if msg != nil {
   144  		msg.Init()
   145  		gMsgPool.Put(msg)
   146  	}
   147  }
   148  
   149  /*
   150  	func (msg *Msg) MarshalAttrElem(attrID uint32, src PbValue) error {
   151  		msg.AttrID = attrID
   152  		sz := src.Size()
   153  		if sz > cap(msg.ValBuf) {
   154  			msg.ValBuf = make([]byte, sz, (sz+0x3FF)&^0x3FF)
   155  		} else {
   156  			msg.ValBuf = msg.ValBuf[:sz]
   157  		}
   158  		_, err := src.MarshalToSizedBuffer(msg.ValBuf)
   159  		return err
   160  	}
   161  
   162  	func (msg *Msg) UnmarshalValue(dst PbValue) error {
   163  		return dst.Unmarshal(msg.ValBuf)
   164  	}
   165  
   166  	func (attr AttrElem) MarshalToMsg(id CellID) (*Msg, error) {
   167  		msg := NewMsg()
   168  		msg.Op = MsgOp_PushAttrElem
   169  		msg.AttrID = attr.AttrID
   170  		msg.SI = attr.SI
   171  		msg.CellID = int64(id)
   172  		err := attr.Val.MarshalToBuf(&msg.ValBuf)
   173  		return msg, err
   174  	}
   175  */
   176  
   177  // type CellMarshaller struct {
   178  // 	Txs []*CellTxPb
   179  
   180  // 	marshalBuf []byte
   181  // 	fatalErr   error
   182  // }
   183  
   184  var gMsgPool = sync.Pool{
   185  	New: func() interface{} {
   186  		return &Msg{}
   187  	},
   188  }
   189  
   190  func (tx *CellTx) Marshal(attrID uint32, SI int64, val ElemVal) {
   191  	if val == nil || attrID == 0 {
   192  		return
   193  	}
   194  
   195  	pb := &AttrElemPb{
   196  		AttrID: uint64(attrID),
   197  		SI:     SI,
   198  	}
   199  	err := val.MarshalToBuf(&pb.ValBuf)
   200  	if err != nil {
   201  		panic(err)
   202  	}
   203  
   204  	tx.ElemsPb = append(tx.ElemsPb, pb)
   205  }
   206  
   207  func (tx *CellTx) Clear(op CellTxOp) {
   208  	tx.Op = op
   209  	tx.TargetCell = CellID{}
   210  	//tx.Elems = tx.Elems[:0]
   211  	tx.ElemsPb = tx.ElemsPb[:0]
   212  }
   213  
   214  /*
   215  func (tx *CellTx) MarshalAttrs() error {
   216  	if cap(tx.ElemsPb) < len(tx.Elems) {
   217  		tx.ElemsPb = make([]*AttrElemPb, len(tx.Elems))
   218  	} else {
   219  		tx.ElemsPb = tx.ElemsPb[:len(tx.Elems)]
   220  	}
   221  	for j, srcELem := range tx.Elems {
   222  		elem := tx.ElemsPb[j]
   223  		if elem == nil {
   224  			elem = &AttrElemPb{}
   225  			tx.ElemsPb[j] = elem
   226  		}
   227  		elem.SI = srcELem.SI
   228  		elem.AttrID = uint64(srcELem.AttrID)
   229  		if err := srcELem.Val.MarshalToBuf(&elem.ValBuf); err != nil {
   230  			return err
   231  		}
   232  	}
   233  	return nil
   234  }
   235  
   236  
   237  func (tx *CellTx) MarshalToPb(dst *CellTxPb) error {
   238  	tx.MarshalAttrs()
   239  	dst.Op = tx.Op
   240  	dst.CellSpec = tx.CellSpec
   241  	dst.TargetCell = int64(tx.TargetCell)
   242  	dst.Elems = tx.ElemsPb
   243  	return nil
   244  }
   245  */
   246  
   247  // If reqID == 0, then this sends an attr to the client's session controller (vs a specific request)
   248  func SendClientMetaAttr(sess HostSession, reqID uint64, val ElemVal) error {
   249  	msg, err := FormClientMetaAttrMsg(sess, val.TypeName(), val)
   250  	msg.ReqID = reqID
   251  	if err != nil {
   252  		return err
   253  	}
   254  	return sess.SendMsg(msg)
   255  }
   256  
   257  func FormClientMetaAttrMsg(reg SessionRegistry, attrSpec string, val ElemVal) (*Msg, error) {
   258  	spec, err := reg.ResolveAttrSpec(attrSpec, false)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	return FormMetaAttrTx(spec, val)
   264  }
   265  
   266  func FormMetaAttrTx(attrSpec AttrSpec, val ElemVal) (*Msg, error) {
   267  	elemPb := &AttrElemPb{
   268  		AttrID: uint64(attrSpec.DefID),
   269  	}
   270  	if err := val.MarshalToBuf(&elemPb.ValBuf); err != nil {
   271  		return nil, err
   272  	}
   273  
   274  	tx := &CellTxPb{
   275  		Op: CellTxOp_MetaAttr,
   276  		Elems: []*AttrElemPb{
   277  			elemPb,
   278  		},
   279  	}
   280  
   281  	msg := NewMsg()
   282  	msg.ReqID = 0 // signals a meta message
   283  	msg.Status = ReqStatus_Synced
   284  	msg.CellTxs = append(msg.CellTxs, tx)
   285  	return msg, nil
   286  }
   287  
   288  func (msg *Msg) GetMetaAttr() (attr *AttrElemPb, err error) {
   289  	if len(msg.CellTxs) == 0 || msg.CellTxs[0].Op != CellTxOp_MetaAttr || msg.CellTxs[0].Elems == nil || len(msg.CellTxs[0].Elems) == 0 {
   290  		return nil, ErrCode_MalformedTx.Error("missing meta attr")
   291  	}
   292  
   293  	return msg.CellTxs[0].Elems[0], nil
   294  }
   295  
   296  func (tx *MultiTx) UnmarshalFrom(msg *Msg, reg SessionRegistry, native bool) error {
   297  	tx.ReqID = msg.ReqID
   298  	tx.Status = msg.Status
   299  	tx.CellTxs = tx.CellTxs[:0]
   300  
   301  	elemCount := 0
   302  
   303  	srcTxs := msg.CellTxs
   304  	if cap(tx.CellTxs) < len(srcTxs) {
   305  		tx.CellTxs = make([]CellTx, len(srcTxs))
   306  	} else {
   307  		tx.CellTxs = tx.CellTxs[:len(srcTxs)]
   308  	}
   309  	for i, cellTx := range srcTxs {
   310  		elems := make([]AttrElem, len(cellTx.Elems))
   311  		for j, srcElem := range cellTx.Elems {
   312  			attrID := uint32(srcElem.AttrID)
   313  			elem := AttrElem{
   314  				SI:     srcElem.SI,
   315  				AttrID: attrID,
   316  			}
   317  			var err error
   318  			elem.Val, err = reg.NewAttrElem(attrID, native)
   319  			if err == nil {
   320  				err = elem.Val.Unmarshal(srcElem.ValBuf)
   321  			}
   322  			if err != nil {
   323  				return err
   324  			}
   325  			elems[j] = elem
   326  			elemCount++
   327  		}
   328  
   329  		tx.CellTxs[i] = CellTx{
   330  			Op: cellTx.Op,
   331  			//Elems:      elems,
   332  		}
   333  		tx.CellTxs[i].TargetCell.AssignFromU64(cellTx.CellID_0, cellTx.CellID_1)
   334  	}
   335  
   336  	if elemCount == 0 {
   337  		return ErrBadCellTx
   338  	}
   339  	return nil
   340  }
   341  
   342  /*
   343  // Pushes a attr mutation to the client, returning true if the msg was sent (false if the client has been closed).
   344  func (bat *CellTx) PushBatch(ctx PinContext) error {
   345  
   346  	for _, attr := range bat.Attrs {
   347  		msg, err := attr.MarshalToMsg(bat.Target)
   348  		if err != nil {
   349  			ctx.Warnf("MarshalToMsg() err: %v", err)
   350  			continue
   351  		}
   352  
   353  		// if i == len(bat.Attrs)-1 {
   354  		// 	msg.Flags |= MsgFlags_CellCheckpoint
   355  		// }
   356  
   357  		if !ctx.PushUpdate(msg) {
   358  			return ErrPinCtxClosed
   359  		}
   360  	}
   361  
   362  	return nil
   363  
   364  }
   365  
   366  
   367  func (tx *MultiTx) MarshalToBuf(dst *[]byte) error {
   368  	pb := MultiTxPb{
   369  		ReqID:   tx.ReqID,
   370  		CellTxs: make([]*CellTxPb, len(tx.CellTxs)),
   371  	}
   372  	for i, srcTx := range tx.CellTxs {
   373  		cellTx := &CellTxPb{
   374  			Op:           srcTx.Op,
   375  			CellSpec:     srcTx.CellSpec,
   376  			TargetCellID: int64(srcTx.Target),
   377  			Elems:        make([]*AttrElemPb, len(srcTx.Elems)),
   378  		}
   379  		for j, attrElem := range srcTx.Elems {
   380  			//attrElem.ValBuf = make([]byte, attrElem.Val.Marhal
   381  			elem := &AttrElemPb{
   382  				SI:     attrElem.SI,
   383  				AttrID: attrElem.AttrID,
   384  			}
   385  			attrElem.Val.MarshalToBuf(&elem.ValBuf)
   386  			cellTx.Elems[j] = elem
   387  		}
   388  		pb.CellTxs[i] = cellTx
   389  	}
   390  	sz := pb.Size()
   391  	if cap(*dst) < sz {
   392  		*dst = make([]byte, sz)
   393  	} else {
   394  		*dst = (*dst)[:sz]
   395  	}
   396  	_, err := pb.MarshalToSizedBuffer(*dst)
   397  	return err
   398  }
   399  
   400  
   401  
   402  func (v *MultiTxPb) MarshalToBuf(dst *[]byte) error {
   403  	return MarshalPbValueToBuf(v, dst)
   404  }
   405  
   406  func (v *MultiTxPb) TypeName() string {
   407  	return "MultiTx"
   408  }
   409  
   410  func (v *MultiTxPb) New() ElemVal {
   411  	return &MultiTxPb{}
   412  }
   413  
   414  */