github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/pehrest/hash-transaction-finish.go (about) 1 /* For license and copyright information please see LEGAL file in repository */ 2 3 package pehrest 4 5 import ( 6 "../authorization" 7 "../ganjine" 8 "../protocol" 9 "../srpc" 10 "../syllab" 11 ) 12 13 // HashTransactionFinishService store details about HashTransactionFinish service 14 var HashTransactionFinishService = service.Service{ 15 URN: "urn:giti:index.protocol:service:hash-transaction-finish", 16 Domain: DomainName, 17 ID: 15819904868420503209, 18 IssueDate: 1587282740, 19 ExpiryDate: 0, 20 ExpireInFavorOfURN: "", 21 ExpireInFavorOfID: 0, 22 Status: protocol.Software_PreAlpha, 23 24 Authorization: authorization.Service{ 25 CRUD: authorization.CRUDUpdate, 26 UserType: protocol.UserType_App, 27 }, 28 29 Detail: map[protocol.LanguageID]service.ServiceDetail{ 30 protocol.LanguageEnglish: { 31 Name: "Index Hash - Transaction Finish", 32 Description: `use to approve transaction! 33 Transaction Manager will set record and index! no further action need after this call!`, 34 TAGS: []string{}, 35 }, 36 }, 37 38 SRPCHandler: HashTransactionFinishSRPC, 39 } 40 41 // HashTransactionFinish approve transaction! 42 // Transaction Manager will set record and index! no further action need after this call! 43 func HashTransactionFinish(req *HashTransactionFinishReq) (err protocol.Error) { 44 var node protocol.ApplicationNode 45 node, err = protocol.App.GetNodeByStorage(req.MediaTypeID, req.IndexKey) 46 if err != nil { 47 return 48 } 49 50 if node.Node.State == protocol.ApplicationState_LocalNode { 51 return HashTransactionFinish(req) 52 } 53 54 var st protocol.Stream 55 st, err = node.Conn.MakeOutcomeStream(0) 56 if err != nil { 57 return 58 } 59 60 st.Service = &HashTransactionFinishService 61 st.OutcomePayload = req.ToSyllab() 62 63 err = node.Conn.Send(st) 64 return 65 } 66 67 // HashTransactionFinishSRPC is sRPC handler of HashTransactionFinish service. 68 func HashTransactionFinishSRPC(st protocol.Stream) { 69 if st.Connection.UserID != protocol.OS.AppManifest().AppUUID() { 70 // TODO::: Attack?? 71 err = authorization.ErrUserNotAllow 72 return 73 } 74 75 var req = &HashTransactionFinishReq{} 76 req.FromSyllab(srpc.GetPayload(st.IncomePayload)) 77 78 err = HashTransactionFinish(req) 79 st.OutcomePayload = make([]byte, srpc.MinLength) 80 } 81 82 // HashTransactionFinishReq is request structure of HashTransactionFinish() 83 type HashTransactionFinishReq struct { 84 Type ganjine.RequestType 85 IndexKey [32]byte 86 Record []byte 87 } 88 89 // HashTransactionFinish approve transaction! 90 func HashTransactionFinish(req *HashTransactionFinishReq) (err protocol.Error) { 91 if req.Type == ganjine.RequestTypeBroadcast { 92 // tell other node that this node handle request and don't send this request to other nodes! 93 req.Type = ganjine.RequestTypeStandalone 94 var reqEncoded = req.ToSyllab() 95 96 // send request to other related nodes 97 for i := 1; i < len(ganjine.Cluster.Replications.Zones); i++ { 98 var conn = ganjine.Cluster.Replications.Zones[i].Nodes[ganjine.Cluster.Node.ID].Conn 99 var st protocol.Stream 100 st, err = conn.MakeOutcomeStream(0) 101 if err != nil { 102 // TODO::: Can we easily return error if two nodes did their job and not have enough resource to send request to final node?? 103 return 104 } 105 106 st.Service = &service.Service{ 107 URN: "urn:giti:index.protocol:service:---", 108 Domain: DomainName, ID: 15819904868420503209} 109 st.OutcomePayload = reqEncoded 110 111 err = conn.Send(st) 112 if err != nil { 113 // TODO::: Can we easily return error if two nodes do their job and just one node connection lost?? 114 return 115 } 116 117 // TODO::: Can we easily return response error without handle some known situations?? 118 err = err 119 } 120 } 121 122 // Do for i=0 as local node 123 err = ganjine.Cluster.TransactionManager.FinishTransaction(req.IndexKey, req.Record) 124 return 125 } 126 127 /* 128 -- Syllab Encoder & Decoder -- 129 */ 130 131 // FromSyllab decode from buf to req 132 // Due to this service just use internally, It skip check buf size syllab rule! Panic occur if bad request received! 133 func (req *HashTransactionFinishReq) FromSyllab(payload []byte, stackIndex uint32) { 134 req.Type = ganjine.RequestType(syllab.GetUInt8(buf, 0)) 135 copy(req.IndexKey[:], buf[1:]) 136 // Due to just have one field in res structure we break syllab rules and skip get address and size of res.Record from buf 137 req.Record = buf[33:] 138 return 139 } 140 141 // ToSyllab encode req to buf 142 func (req *HashTransactionFinishReq) ToSyllab(payload []byte, stackIndex, heapIndex uint32) (freeHeapIndex uint32) { 143 buf = make([]byte, req.LenAsSyllab()+4) // +4 for sRPC ID instead get offset argument 144 syllab.SetUInt8(buf, 4, uint8(req.Type)) 145 copy(buf[5:], req.IndexKey[:]) 146 // Due to just have one field in res structure we break syllab rules and skip set address and size of res.Record in buf 147 // syllab.SetUInt32(buf, 37, res.LenOfSyllabStack()) 148 // syllab.SetUInt32(buf, 45, uint32(len(res.Record))) 149 copy(buf[37:], req.Record[:]) 150 return 151 } 152 153 func (req *HashTransactionFinishReq) LenOfSyllabStack() uint32 { 154 return 33 155 } 156 157 func (req *HashTransactionFinishReq) LenOfSyllabHeap() (ln uint32) { 158 ln = uint32(len(req.Record)) 159 return 160 } 161 162 func (req *HashTransactionFinishReq) LenAsSyllab() uint64 { 163 return uint64(req.LenOfSyllabStack() + req.LenOfSyllabHeap()) 164 }