From 1cfbcabae3e3fc51aca3edd61ce8934a4bf8b3f0 Mon Sep 17 00:00:00 2001
From: Jono Wenger <jono@elixxir.io>
Date: Thu, 4 Mar 2021 23:09:32 +0000
Subject: [PATCH] Add InProgressRegistrations to the network manager, which
 returns the number of in progress node registrations

---
 api/client.go                  | 20 ++++++++++++++++++++
 api/utilsInterfaces_test.go    |  4 ++++
 bindings/client.go             |  8 ++++++++
 bindings/registrationStatus.go | 25 +++++++++++++++++++++++++
 interfaces/networkManager.go   |  1 +
 keyExchange/utils_test.go      |  8 ++++++++
 network/ephemeral/testutil.go  |  4 ++++
 network/manager.go             |  5 +++++
 single/manager_test.go         |  4 ++++
 storage/cmix/store.go          |  7 +++++++
 storage/cmix/store_test.go     | 28 +++++++++++++++++++++++++++-
 11 files changed, 113 insertions(+), 1 deletion(-)
 create mode 100644 bindings/registrationStatus.go

diff --git a/api/client.go b/api/client.go
index 4ae049f72..2c83ad2af 100644
--- a/api/client.go
+++ b/api/client.go
@@ -485,6 +485,26 @@ func (c *Client) GetNetworkInterface() interfaces.NetworkManager {
 	return c.network
 }
 
+// GetNodeRegistrationStatus gets the current status of node registration. It
+// returns the number of nodes that the client is registered and the number of
+// in progress node registrations. An error is returned if the network is not
+// healthy.
+func (c *Client) GetNodeRegistrationStatus() (int, int, error) {
+	// Return an error if the network is not healthy
+	if !c.GetHealth().IsHealthy() {
+		return 0, 0, errors.New("Cannot get number of node registrations when " +
+			"network is not healthy")
+	}
+
+	// Get the number of nodes that client is registered with
+	registeredNodes := c.storage.Cmix().Count()
+
+	// Get the number of in progress node registrations
+	inProgress := c.network.InProgressRegistrations()
+
+	return registeredNodes, inProgress, nil
+}
+
 // ----- Utility Functions -----
 // parseNDF parses the initial ndf string for the client. do not check the
 // signature, it is deprecated.
diff --git a/api/utilsInterfaces_test.go b/api/utilsInterfaces_test.go
index 6eb4c466a..95ba3b1e6 100644
--- a/api/utilsInterfaces_test.go
+++ b/api/utilsInterfaces_test.go
@@ -115,3 +115,7 @@ func (t *testNetworkManagerGeneric) GetRemoteVersion() (string, error) {
 func (t *testNetworkManagerGeneric) GetStoppable() stoppable.Stoppable {
 	return &stoppable.Multi{}
 }
+
+func (t *testNetworkManagerGeneric) InProgressRegistrations() int {
+	return 0
+}
diff --git a/bindings/client.go b/bindings/client.go
index 431c86083..8cd54bf7a 100644
--- a/bindings/client.go
+++ b/bindings/client.go
@@ -338,6 +338,14 @@ func (c *Client) GetUser() *User {
 	return &User{u: &u}
 }
 
+// GetNodeRegistrationStatus returns a struct with the number of nodes the
+// client is registered with and the number of in progress registrations.
+func (c *Client) GetNodeRegistrationStatus() (*NodeRegistrationsStatus, error) {
+	registered, inProgress, err := c.api.GetNodeRegistrationStatus()
+
+	return &NodeRegistrationsStatus{registered, inProgress}, err
+}
+
 /*
 // SearchWithHandler is a non-blocking search that also registers
 // a callback interface for user disovery events.
diff --git a/bindings/registrationStatus.go b/bindings/registrationStatus.go
new file mode 100644
index 000000000..224463764
--- /dev/null
+++ b/bindings/registrationStatus.go
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+// NodeRegistrationsStatus structure for returning node registration statuses
+// for bindings.
+type NodeRegistrationsStatus struct {
+	registered int
+	inProgress int
+}
+
+// GetRegistered returns the number of nodes registered with the client.
+func (nrs *NodeRegistrationsStatus) GetRegistered() int {
+	return nrs.registered
+}
+
+// GetInProgress return the number of nodes currently registering.
+func (nrs *NodeRegistrationsStatus) GetInProgress() int {
+	return nrs.inProgress
+}
diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go
index b7ff3a886..9e652e536 100644
--- a/interfaces/networkManager.go
+++ b/interfaces/networkManager.go
@@ -26,6 +26,7 @@ type NetworkManager interface {
 	GetHealthTracker() HealthTracker
 	Follow() (stoppable.Stoppable, error)
 	CheckGarbledMessages()
+	InProgressRegistrations() int
 }
 
 //for use in key exchange which needs to be callable inside of network
diff --git a/keyExchange/utils_test.go b/keyExchange/utils_test.go
index bda05f0b8..1b61b84c1 100644
--- a/keyExchange/utils_test.go
+++ b/keyExchange/utils_test.go
@@ -99,6 +99,10 @@ func (t *testNetworkManagerGeneric) GetStoppable() stoppable.Stoppable {
 	return &stoppable.Multi{}
 }
 
+func (t *testNetworkManagerGeneric) InProgressRegistrations() int {
+	return 0
+}
+
 func InitTestingContextGeneric(i interface{}) (*storage.Session, interfaces.NetworkManager) {
 	switch i.(type) {
 	case *testing.T, *testing.M, *testing.B, *testing.PB:
@@ -202,6 +206,10 @@ func (t *testNetworkManagerFullExchange) GetStoppable() stoppable.Stoppable {
 	return &stoppable.Multi{}
 }
 
+func (t *testNetworkManagerFullExchange) InProgressRegistrations() int {
+	return 0
+}
+
 func InitTestingContextFullExchange(i interface{}) (*storage.Session, *switchboard.Switchboard, interfaces.NetworkManager) {
 	switch i.(type) {
 	case *testing.T, *testing.M, *testing.B, *testing.PB:
diff --git a/network/ephemeral/testutil.go b/network/ephemeral/testutil.go
index 1691ae8bd..18d82e6fc 100644
--- a/network/ephemeral/testutil.go
+++ b/network/ephemeral/testutil.go
@@ -74,6 +74,10 @@ func (t *testNetworkManager) Follow() (stoppable.Stoppable, error) {
 
 func (t *testNetworkManager) CheckGarbledMessages() {}
 
+func (t *testNetworkManager) InProgressRegistrations() int {
+	return 0
+}
+
 func NewTestNetworkManager(i interface{}) interfaces.NetworkManager {
 	switch i.(type) {
 	case *testing.T, *testing.M, *testing.B:
diff --git a/network/manager.go b/network/manager.go
index 7df9c58d9..c37089497 100644
--- a/network/manager.go
+++ b/network/manager.go
@@ -167,3 +167,8 @@ func (m *manager) GetInstance() *network.Instance {
 func (m *manager) CheckGarbledMessages() {
 	m.message.CheckGarbledMessages()
 }
+
+// InProgressRegistrations returns the number of in progress node registrations.
+func (m *manager) InProgressRegistrations() int {
+	return len(m.Internal.NodeRegistration) + 1
+}
diff --git a/single/manager_test.go b/single/manager_test.go
index 33427010d..b8dc30e6d 100644
--- a/single/manager_test.go
+++ b/single/manager_test.go
@@ -318,6 +318,10 @@ func (tnm *testNetworkManager) Follow() (stoppable.Stoppable, error) {
 
 func (tnm *testNetworkManager) CheckGarbledMessages() {}
 
+func (tnm *testNetworkManager) InProgressRegistrations() int {
+	return 0
+}
+
 func getNDF() *ndf.NetworkDefinition {
 	return &ndf.NetworkDefinition{
 		E2E: ndf.Group{
diff --git a/storage/cmix/store.go b/storage/cmix/store.go
index cc03ebcf3..47e1503a6 100644
--- a/storage/cmix/store.go
+++ b/storage/cmix/store.go
@@ -185,6 +185,13 @@ func (s *Store) IsRegistered(nid *id.ID) bool {
 	return ok
 }
 
+// Count returns the number of registered nodes.
+func (s *Store) Count() int {
+	s.mux.RLock()
+	defer s.mux.RUnlock()
+	return len(s.nodes)
+}
+
 // save stores the cMix store.
 func (s *Store) save() error {
 	now := time.Now()
diff --git a/storage/cmix/store_test.go b/storage/cmix/store_test.go
index 92d8754db..8e05e0c39 100644
--- a/storage/cmix/store_test.go
+++ b/storage/cmix/store_test.go
@@ -160,7 +160,33 @@ func TestStore_GetRoundKeys_Missing(t *testing.T) {
 	}
 }
 
-// Main testing function
+// Happy path.
+func TestStore_Count(t *testing.T) {
+	vkv := versioned.NewKV(make(ekv.Memstore))
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+
+	store, err := NewStore(grp, vkv, grp.NewInt(2))
+	if err != nil {
+		t.Fatalf("Failed to generate new Store: %+v", err)
+	}
+
+	if store.Count() != 0 {
+		t.Errorf("Count() did not return the expected value for a new Store."+
+			"\nexpected: %d\nreceived: %d", 0, store.Count())
+	}
+
+	count := 50
+	for i := 0; i < count; i++ {
+		store.Add(id.NewIdFromUInt(uint64(i), id.Node, t), grp.NewInt(int64(42+i)))
+	}
+
+	if store.Count() != count {
+		t.Errorf("Count() did not return the expected value."+
+			"\nexpected: %d\nreceived: %d", count, store.Count())
+	}
+}
+
+// Main testing function.
 func makeTestStore() (*Store, *versioned.KV) {
 
 	kv := make(ekv.Memstore)
-- 
GitLab