github.com/git-amp/amp-sdk-go@v0.7.5/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 */