Skip to content

Commit

Permalink
Add RemoteNodeIndexer
Browse files Browse the repository at this point in the history
  • Loading branch information
AeonSw4n committed Dec 28, 2023
1 parent 1921254 commit 8488f83
Show file tree
Hide file tree
Showing 3 changed files with 509 additions and 3 deletions.
237 changes: 237 additions & 0 deletions lib/remote_node_indexer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
package lib

import "github.com/deso-protocol/core/bls"

// RemoteNodeIndexId is a custom string type used for identifying different types of remote node indices.
type RemoteNodeIndexId string

// Constants for different types of remote node indices.
const (
RemoteNodeIndexId_Default RemoteNodeIndexId = "DEFAULT"
RemoteNodeIndexId_Validator RemoteNodeIndexId = "VALIDATOR"
RemoteNodeIndexId_ValidatorAttempted RemoteNodeIndexId = "VALIDATOR_ATTEMPTED"
RemoteNodeIndexId_NonValidator_Outbound RemoteNodeIndexId = "NONVALIDATOR_OUTBOUND"
RemoteNodeIndexId_NonValidator_Inbound RemoteNodeIndexId = "NONVALIDATOR_INBOUND"
RemoteNodeIndexId_NonValidator_Attempted RemoteNodeIndexId = "NONVALIDATOR_ATTEMPTED"
)

// RemoteNodeIndexer is a structure that holds information about all remote nodes and their indices.
type RemoteNodeIndexer struct {
// AllRemoteNodes is a map storing all remote nodes by their IDs.
AllRemoteNodes *RemoteNodeIndex[RemoteNodeId]

// Indices for various types of remote nodes.
ValidatorIndex *RemoteNodeIndex[bls.PublicKey]
ValidatorAttemptedIndex *RemoteNodeIndex[bls.PublicKey]
NonValidatorOutboundIndex *RemoteNodeIndex[RemoteNodeId]
NonValidatorInboundIndex *RemoteNodeIndex[RemoteNodeId]
NonValidatorAttemptedIndex *RemoteNodeIndex[RemoteNodeId]

// RemoteNodeToIndexIdList maps remote nodes to their corresponding index IDs.
RemoteNodeToIndexIdList map[*RemoteNode][]RemoteNodeIndexId

RemoteNodeToIndexRemoveFuncList map[*RemoteNode][]RemoteNodeIndexRemoveFunc
}

// NewRemoteNodeIndexer initializes and returns a new instance of RemoteNodeIndexer.
func NewRemoteNodeIndexer() *RemoteNodeIndexer {
rni := &RemoteNodeIndexer{
RemoteNodeToIndexIdList: make(map[*RemoteNode][]RemoteNodeIndexId),
RemoteNodeToIndexRemoveFuncList: make(map[*RemoteNode][]RemoteNodeIndexRemoveFunc),
}

// Initializing various indices with their respective types and update callback.
rni.AllRemoteNodes = NewRemoteNodeIndex[RemoteNodeId](RemoteNodeIndexId_Default, rni.updateCallback)
rni.ValidatorIndex = NewRemoteNodeIndex[bls.PublicKey](RemoteNodeIndexId_Validator, rni.updateCallback)
rni.ValidatorAttemptedIndex = NewRemoteNodeIndex[bls.PublicKey](RemoteNodeIndexId_ValidatorAttempted, rni.updateCallback)
rni.NonValidatorOutboundIndex = NewRemoteNodeIndex[RemoteNodeId](RemoteNodeIndexId_NonValidator_Outbound, rni.updateCallback)
rni.NonValidatorInboundIndex = NewRemoteNodeIndex[RemoteNodeId](RemoteNodeIndexId_NonValidator_Inbound, rni.updateCallback)
rni.NonValidatorAttemptedIndex = NewRemoteNodeIndex[RemoteNodeId](RemoteNodeIndexId_NonValidator_Attempted, rni.updateCallback)
return rni
}

// Getter methods for accessing the different indices.
func (rni *RemoteNodeIndexer) GetAllRemoteNodes() RemoteNodeIndexInterface[RemoteNodeId] {
return rni.AllRemoteNodes
}

func (rni *RemoteNodeIndexer) GetValidatorIndex() RemoteNodeIndexInterface[bls.PublicKey] {
return rni.ValidatorIndex
}

func (rni *RemoteNodeIndexer) GetValidatorAttemptedIndex() RemoteNodeIndexInterface[bls.PublicKey] {
return rni.ValidatorAttemptedIndex
}

func (rni *RemoteNodeIndexer) GetNonValidatorOutboundIndex() RemoteNodeIndexInterface[RemoteNodeId] {
return rni.NonValidatorOutboundIndex
}

func (rni *RemoteNodeIndexer) GetNonValidatorInboundIndex() RemoteNodeIndexInterface[RemoteNodeId] {
return rni.NonValidatorInboundIndex
}

func (rni *RemoteNodeIndexer) GetNonValidatorAttemptedIndex() RemoteNodeIndexInterface[RemoteNodeId] {
return rni.NonValidatorAttemptedIndex
}

// Getter methods for AllRemoteNodes
func (rni *RemoteNodeIndexer) GetRemoteNodeFromPeer(peer *Peer) *RemoteNode {
if peer == nil {
return nil
}

id := NewRemoteNodeId(peer.GetId())
return rni.GetRemoteNodeFromId(id)
}

func (rni *RemoteNodeIndexer) GetRemoteNodeFromId(id RemoteNodeId) *RemoteNode {
rn, ok := rni.GetAllRemoteNodes().Get(id)
if !ok {
return nil
}
return rn
}

func (rni *RemoteNodeIndexer) SetRemoteNode(rn *RemoteNode) {
if rn == nil {
return
}

rni.GetAllRemoteNodes().Add(rn.GetId(), rn)
}

func (rni *RemoteNodeIndexer) RemoveRemoteNode(rn *RemoteNode) {
if rn == nil {
return
}

if _, ok := rni.RemoteNodeToIndexRemoveFuncList[rn]; !ok {
return
}

for _, removeFunc := range rni.RemoteNodeToIndexRemoveFuncList[rn] {
if removeFunc == nil {
continue
}
removeFunc()
}
}

// updateCallback is invoked when a node is added or removed from an index.
func (rni *RemoteNodeIndexer) updateCallback(id RemoteNodeIndexId, node *RemoteNode, isAdd bool, removeFunc RemoteNodeIndexRemoveFunc) {
if isAdd {
rni.RemoteNodeToIndexIdList[node] = append(rni.RemoteNodeToIndexIdList[node], id)
rni.RemoteNodeToIndexRemoveFuncList[node] = append(rni.RemoteNodeToIndexRemoveFuncList[node], removeFunc)
} else {
var indexId RemoteNodeIndexId
pos := 0

for pos, indexId = range rni.RemoteNodeToIndexIdList[node] {
if indexId == id {
rni.RemoteNodeToIndexIdList[node] = append(rni.RemoteNodeToIndexIdList[node][:pos], rni.RemoteNodeToIndexIdList[node][pos+1:]...)
break
}
}

rni.RemoteNodeToIndexRemoveFuncList[node] = append(rni.RemoteNodeToIndexRemoveFuncList[node][:pos], rni.RemoteNodeToIndexRemoveFuncList[node][pos+1:]...)
}
}

// RemoteNodeIndexInterface defines the methods for a remote node index.
type RemoteNodeIndexInterface[Key comparable] interface {
GetId() RemoteNodeIndexId
Add(key Key, node *RemoteNode)
Remove(key Key)
Get(key Key) (*RemoteNode, bool)
GetRandom() (*RemoteNode, bool)
GetIndex() map[Key]*RemoteNode
GetAll() []*RemoteNode
}

// RemoteNodeIndex holds an index of remote nodes by a specific key type.
type RemoteNodeIndex[Key comparable] struct {
Id RemoteNodeIndexId
Index map[Key]*RemoteNode
updateCallback RemoteNodeIndexCallback
}

// RemoteNodeIndexRemoveFunc is a function type for removal of a RemoteNode from the Index.
type RemoteNodeIndexRemoveFunc func()

// RemoteNodeIndexCallback is a function type for update callbacks.
type RemoteNodeIndexCallback func(id RemoteNodeIndexId, node *RemoteNode, isAdd bool, removeFunc RemoteNodeIndexRemoveFunc)

// NewRemoteNodeIndex creates and returns a new RemoteNodeIndex.
func NewRemoteNodeIndex[Key comparable](id RemoteNodeIndexId, updateCallback RemoteNodeIndexCallback) *RemoteNodeIndex[Key] {
return &RemoteNodeIndex[Key]{
Id: id,
Index: make(map[Key]*RemoteNode),
updateCallback: updateCallback,
}
}

// Implementations of the RemoteNodeIndexInterface methods.
func (rni *RemoteNodeIndex[Key]) GetId() RemoteNodeIndexId {
return rni.Id
}

func (rni *RemoteNodeIndex[Key]) Add(key Key, node *RemoteNode) {
rni.Index[key] = node

// Define the remove function
removeFunc := func() {
if _, ok := rni.Index[key]; !ok {
return
}
delete(rni.Index, key)
}

if rni.updateCallback != nil {
rni.updateCallback(rni.Id, node, true, removeFunc)
}
}

func (rni *RemoteNodeIndex[Key]) Remove(key Key) {
rn, ok := rni.Index[key]
if !ok {
return
}
delete(rni.Index, key)
if rni.updateCallback != nil {
rni.updateCallback(rni.Id, rn, false, nil)
}
}

func (rni *RemoteNodeIndex[Key]) Get(key Key) (*RemoteNode, bool) {
elem, ok := rni.Index[key]
return elem, ok
}

func (rni *RemoteNodeIndex[Key]) GetRandom() (*RemoteNode, bool) {
if len(rni.Index) == 0 {
return nil, false
}

var node *RemoteNode
for _, node = range rni.Index {
break
}
return node, true
}

func (rni *RemoteNodeIndex[Key]) GetIndex() map[Key]*RemoteNode {
index := make(map[Key]*RemoteNode)
for key, node := range rni.Index {
index[key] = node
}
return index
}

func (rni *RemoteNodeIndex[Key]) GetAll() []*RemoteNode {
var nodes []*RemoteNode
for _, node := range rni.Index {
nodes = append(nodes, node)
}
return nodes
}
Loading

0 comments on commit 8488f83

Please sign in to comment.