github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/pehrest/hash-insert-value.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  // HashInsertValueService store details about HashInsertValue service
    14  var HashInsertValueService = service.Service{
    15  	URN:                "urn:giti:index.protocol:service:hash-insert-value",
    16  	Domain:             DomainName,
    17  	ID:                 5503704311120461517,
    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 - Insert Value",
    32  			Description: "Add given RecordID to the given hash index in order and return error if it is exist already!",
    33  			TAGS:        []string{},
    34  		},
    35  	},
    36  
    37  	SRPCHandler: HashInsertValueSRPC,
    38  }
    39  
    40  // HashInsertValue set a record ID to new||exiting index hash just if not exist before!
    41  func HashInsertValue(req *HashInsertValueReq) (err protocol.Error) {
    42  	var node protocol.ApplicationNode
    43  	node, err = protocol.App.GetNodeByStorage(req.MediaTypeID, req.IndexKey)
    44  	if err != nil {
    45  		return
    46  	}
    47  
    48  	if node.Node.State == protocol.ApplicationState_LocalNode {
    49  		err = HashInsertValue(req)
    50  		return
    51  	}
    52  
    53  	var st protocol.Stream
    54  	st, err = node.Conn.MakeOutcomeStream(0)
    55  	if err != nil {
    56  		return
    57  	}
    58  
    59  	st.Service = &HashInsertValueService
    60  	st.OutcomePayload = req.ToSyllab()
    61  
    62  	err = node.Conn.Send(st)
    63  	return
    64  }
    65  
    66  // HashInsertValueSRPC is sRPC handler of HashInsertValue service.
    67  func HashInsertValueSRPC(st protocol.Stream) {
    68  	if st.Connection.UserID != protocol.OS.AppManifest().AppUUID() {
    69  		// TODO::: Attack??
    70  		err = authorization.ErrUserNotAllow
    71  		return
    72  	}
    73  
    74  	var req = HashInsertValueReq{}
    75  	req.FromSyllab(srpc.GetPayload(st.IncomePayload))
    76  
    77  	err = HashInsertValue(&req)
    78  	st.OutcomePayload = make([]byte, srpc.MinLength)
    79  }
    80  
    81  // HashInsertValueReq is request structure of HashInsertValue()
    82  type HashInsertValueReq struct {
    83  	Type       ganjine.RequestType
    84  	IndexKey   [32]byte
    85  	IndexValue [32]byte // can be RecordID or any data up to 32 byte length
    86  }
    87  
    88  // HashInsertValue set a record ID to new||exiting index hash.
    89  func HashInsertValue(req *HashInsertValueReq) (err protocol.Error) {
    90  	if req.Type == ganjine.RequestTypeBroadcast {
    91  		// tell other node that this node handle request and don't send this request to other nodes!
    92  		req.Type = ganjine.RequestTypeStandalone
    93  		var reqEncoded = req.ToSyllab()
    94  
    95  		// send request to other related nodes
    96  		for i := 1; i < len(ganjine.Cluster.Replications.Zones); i++ {
    97  			var conn = ganjine.Cluster.Replications.Zones[i].Nodes[ganjine.Cluster.Node.ID].Conn
    98  			// Make new request-response streams
    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  			// Set HashInsertValue ServiceID
   107  			st.Service = &service.Service{ID: 1881585857}
   108  			st.OutcomePayload = reqEncoded
   109  
   110  			err = conn.Send(st)
   111  			if err != nil {
   112  				// TODO::: Can we easily return error if two nodes do their job and just one node connection lost??
   113  				return
   114  			}
   115  
   116  			// TODO::: Can we easily return response error without handle some known situations??
   117  			err = err
   118  		}
   119  	}
   120  
   121  	// Do for i=0 as local node
   122  	var hashIndex = IndexHash{
   123  		RecordID: req.IndexKey,
   124  	}
   125  	err = hashIndex.Insert(req.IndexValue)
   126  	return
   127  }
   128  
   129  /*
   130  	-- Syllab Encoder & Decoder --
   131  */
   132  
   133  // FromSyllab decode from buf to req
   134  // Due to this service just use internally, It skip check buf size syllab rule! Panic occur if bad request received!
   135  func (req *HashInsertValueReq) FromSyllab(payload []byte, stackIndex uint32) {
   136  	req.Type = ganjine.RequestType(syllab.GetUInt8(buf, 0))
   137  	copy(req.IndexKey[:], buf[1:])
   138  	copy(req.IndexValue[:], buf[33:])
   139  	return
   140  }
   141  
   142  // ToSyllab encode req to buf
   143  func (req *HashInsertValueReq) ToSyllab(payload []byte, stackIndex, heapIndex uint32) (freeHeapIndex uint32) {
   144  	buf = make([]byte, req.LenAsSyllab()+4) // +4 for sRPC ID instead get offset argument
   145  	syllab.SetUInt8(buf, 4, uint8(req.Type))
   146  	copy(buf[5:], req.IndexKey[:])
   147  	copy(buf[37:], req.IndexValue[:])
   148  	return
   149  }
   150  
   151  func (req *HashInsertValueReq) LenOfSyllabStack() uint32 {
   152  	return 65
   153  }
   154  
   155  func (req *HashInsertValueReq) LenOfSyllabHeap() (ln uint32) {
   156  	return
   157  }
   158  
   159  func (req *HashInsertValueReq) LenAsSyllab() uint64 {
   160  	return uint64(req.LenOfSyllabStack() + req.LenOfSyllabHeap())
   161  }