From a8bb71a4d2d9c3fb7f2559229b768daff747b9e9 Mon Sep 17 00:00:00 2001
From: josh <josh@elixxir.io>
Date: Thu, 14 Apr 2022 13:16:27 -0700
Subject: [PATCH] Restructure bindings for ud/ changes

---
 api/client.go  |  10 +++
 bindings/ud.go | 178 +++++++++++++++++++++++++++++++++++--------------
 2 files changed, 139 insertions(+), 49 deletions(-)

diff --git a/api/client.go b/api/client.go
index 458d4ed47..407f547f5 100644
--- a/api/client.go
+++ b/api/client.go
@@ -721,6 +721,16 @@ func (c *Client) GetNetworkInterface() cmix.Client {
 	return c.network
 }
 
+// GetE2eInterface returns the client e2e Handler.
+func (c *Client) GetE2e() e2e.Handler {
+	return c.e2e
+}
+
+// GetEventManager returns the client e2e Handler.
+func (c *Client) GetEventManager() *event.Manager {
+	return c.events
+}
+
 // GetBackup returns a pointer to the backup container so that the backup can be
 // set and triggered.
 func (c *Client) GetBackup() *backup.Backup {
diff --git a/bindings/ud.go b/bindings/ud.go
index a8dbb9e39..c96cf5a7a 100644
--- a/bindings/ud.go
+++ b/bindings/ud.go
@@ -13,7 +13,7 @@ import (
 	"time"
 
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/ud"
+	udPackage "gitlab.com/elixxir/client/ud"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
@@ -22,26 +22,49 @@ import (
 // This package wraps the user discovery system
 
 type UserDiscovery struct {
-	ud *ud.Manager
+	ud *udPackage.Manager
 }
 
-// NewUserDiscovery returns a new user discovery object. Only call this once. It must be called
-// after StartNetworkFollower is called and will fail if the network has never
-// been contacted.
+// NewUserDiscovery returns a new user discovery object. Only call this once.
+// It must be called after StartNetworkFollower is called and will fail if the
+// network has never been contacted. This will auto-register with the
+// UD service. You should only call this on the first instantiation of the user
+// discovery manager.
 // This function technically has a memory leak because it causes both sides of
 // the bindings to think the other is in charge of the client object.
 // In general this is not an issue because the client object should exist
 // for the life of the program.
 // This must be called while start network follower is running.
-func NewUserDiscovery(client *Client) (*UserDiscovery, error) {
-	single, err := client.getSingle()
+func NewUserDiscovery(client *Client, username string) (*UserDiscovery, error) {
+
+	m, err := udPackage.NewManager(client.api.GetNetworkInterface(),
+		client.api.GetE2e(), client.api.NetworkFollowerStatus,
+		client.api.GetEventManager(),
+		client.api.GetComms(), client.api.GetStorage(),
+		client.api.GetRng(),
+		username, client.api.GetStorage().GetKV())
+
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to create User Discovery Manager")
+		return nil, errors.WithMessage(err,
+			"Failed to create User Discovery Manager")
+	} else {
+		return &UserDiscovery{ud: m}, nil
 	}
-	m, err := ud.NewManager(&client.api, single)
+}
+
+// LoadUserDiscovery loads the state of the UserDiscovery manager
+// from disk. This is meant to be called after any app restart after the first
+// instantiation of the manager by NewUserDiscovery.
+func LoadUserDiscovery(client *Client) (*UserDiscovery, error) {
+	m, err := udPackage.LoadManager(client.api.GetNetworkInterface(),
+		client.api.GetE2e(), client.api.GetEventManager(),
+		client.api.GetComms(), client.api.GetStorage(),
+		client.api.GetRng(),
+		client.api.GetStorage().GetKV())
 
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to create User Discovery Manager")
+		return nil, errors.WithMessage(err,
+			"Failed to load User Discovery Manager")
 	} else {
 		return &UserDiscovery{ud: m}, nil
 	}
@@ -68,12 +91,9 @@ func NewUserDiscovery(client *Client) (*UserDiscovery, error) {
 // This must be called while start network follower is running.
 func NewUserDiscoveryFromBackup(client *Client,
 	email, phone string) (*UserDiscovery, error) {
-	single, err := client.getSingle()
-	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to create User Discovery Manager")
-	}
 
 	var emailFact, phoneFact fact.Fact
+	var err error
 	// Parse email as a fact, if it exists
 	if len(email) > 2 {
 		emailFact, err = fact.UnstringifyFact(email)
@@ -93,26 +113,24 @@ func NewUserDiscoveryFromBackup(client *Client,
 				"stringified phone fact %q", phone)
 		}
 	} else {
-		jww.WARN.Printf("Loading manager without a registered phone number")
+		jww.WARN.Printf("Loading manager without a " +
+			"registered phone number")
 	}
 
-	m, err := ud.NewManagerFromBackup(&client.api, single, phoneFact)
+	m, err := udPackage.NewManagerFromBackup(client.api.GetNetworkInterface(),
+		client.api.GetE2e(), client.api.NetworkFollowerStatus,
+		client.api.GetEventManager(),
+		client.api.GetComms(), client.api.GetStorage(),
+		client.api.GetRng(), emailFact, phoneFact,
+		client.api.GetStorage().GetKV())
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to create User Discovery Manager")
+		return nil, errors.WithMessage(err,
+			"Failed to create User Discovery Manager")
 	} else {
 		return &UserDiscovery{ud: m}, nil
 	}
 }
 
-// Register registers a user with user discovery. Will return an error if the
-// network signatures are malformed or if the username is taken. Usernames
-// cannot be changed after registration at this time. Will fail if the user is
-// already registered.
-// Identity does not go over cmix, it occurs over normal communications
-func (ud *UserDiscovery) Register(username string) error {
-	return ud.ud.Register(username)
-}
-
 // AddFact adds a fact for the user to user discovery. Will only succeed if the
 // user is already registered and the system does not have the fact currently
 // registered for any user.
@@ -131,15 +149,17 @@ func (ud *UserDiscovery) AddFact(fStr string) (string, error) {
 	return ud.ud.SendRegisterFact(f)
 }
 
-// ConfirmFact confirms a fact first registered via AddFact. The confirmation ID comes from
-// AddFact while the code will come over the associated communications system
+// ConfirmFact confirms a fact first registered via AddFact.
+// The confirmation ID comes from AddFact while the code will come over the
+// associated communications system
 func (ud *UserDiscovery) ConfirmFact(confirmationID, code string) error {
 	return ud.ud.ConfirmFact(confirmationID, code)
 }
 
-// RemoveFact removes a previously confirmed fact.  Will fail if the passed fact string is
-// not well-formed or if the fact is not associated with this client.
-// Users cannot remove username facts and must instead remove the user.
+// RemoveFact removes a previously confirmed fact.  Will fail if the
+// passed fact string is not well-formed or if the fact is not associated
+// with this client. Users cannot remove username facts and must instead
+// remove the user.
 func (ud *UserDiscovery) RemoveFact(fStr string) error {
 	f, err := fact.UnstringifyFact(fStr)
 	if err != nil {
@@ -173,11 +193,12 @@ type SearchCallback interface {
 // This is NOT intended to be used to search for multiple users at once, that
 // can have a privacy reduction. Instead, it is intended to be used to search
 // for a user where multiple pieces of information is known.
-func (ud UserDiscovery) Search(fl string, callback SearchCallback,
-	timeoutMS int) error {
+func (ud UserDiscovery) Search(client *Client,
+	fl string, callback SearchCallback,
+	timeoutMS int) (int, error) {
 	factList, _, err := fact.UnstringifyFactList(fl)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to search due to "+
+		return 0, errors.WithMessage(err, "Failed to search due to "+
 			"malformed fact list")
 	}
 	timeout := time.Duration(timeoutMS) * time.Millisecond
@@ -191,7 +212,24 @@ func (ud UserDiscovery) Search(fl string, callback SearchCallback,
 		}
 		callback.Callback(contactList, errStr)
 	}
-	return ud.ud.Search(factList, cb, timeout)
+
+	udContact, err := ud.ud.GetContact()
+	if err != nil {
+		return 0, errors.WithMessage(err, "Failed to get user discovery "+
+			"contact object")
+	}
+
+	rid, _, err := udPackage.Search(
+		client.api.GetNetworkInterface(), client.api.GetEventManager(),
+		client.api.GetRng(), client.api.GetE2e().GetGroup(), udContact,
+		cb, factList, timeout)
+
+	if err != nil {
+		return 0, errors.WithMessagef(err,
+			"Failed to search for facts %q", factList.Stringify())
+	}
+
+	return int(rid), nil
 }
 
 // SingleSearchCallback returns the result of a single search
@@ -205,11 +243,11 @@ type SingleSearchCallback interface {
 // a list of contacts, each having the facts it hit against.
 // This only searches for a single fact at a time. It is intended to make some
 // simple use cases of the API easier.
-func (ud UserDiscovery) SearchSingle(f string, callback SingleSearchCallback,
-	timeoutMS int) error {
+func (ud UserDiscovery) SearchSingle(client *Client, f string, callback SingleSearchCallback,
+	timeoutMS int) (int, error) {
 	fObj, err := fact.UnstringifyFact(f)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to single search due "+
+		return 0, errors.WithMessage(err, "Failed to single search due "+
 			"to malformed fact")
 	}
 	timeout := time.Duration(timeoutMS) * time.Millisecond
@@ -223,7 +261,23 @@ func (ud UserDiscovery) SearchSingle(f string, callback SingleSearchCallback,
 		}
 		callback.Callback(c, errStr)
 	}
-	return ud.ud.Search([]fact.Fact{fObj}, cb, timeout)
+	udContact, err := ud.ud.GetContact()
+	if err != nil {
+		return 0, errors.WithMessage(err, "Failed to get user discovery "+
+			"contact object")
+	}
+
+	rid, _, err := udPackage.Search(client.api.GetNetworkInterface(),
+		client.api.GetEventManager(),
+		client.api.GetRng(), client.api.GetE2e().GetGroup(), udContact,
+		cb, []fact.Fact{fObj}, timeout)
+
+	if err != nil {
+		return 0, errors.WithMessagef(err,
+			"Failed to Search (single) for fact %q", fObj.Stringify())
+	}
+
+	return int(rid), nil
 }
 
 // LookupCallback returns the result of a single lookup
@@ -235,12 +289,13 @@ type LookupCallback interface {
 // id is the byte representation of an id.
 // This will reject if that id is malformed. The LookupCallback will return
 // the associated contact if it exists.
-func (ud UserDiscovery) Lookup(idBytes []byte, callback LookupCallback,
-	timeoutMS int) error {
+func (ud UserDiscovery) Lookup(client *Client,
+	idBytes []byte, callback LookupCallback,
+	timeoutMS int) (int, error) {
 
 	uid, err := id.Unmarshal(idBytes)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to lookup due to "+
+		return 0, errors.WithMessage(err, "Failed to lookup due to "+
 			"malformed id")
 	}
 
@@ -256,7 +311,25 @@ func (ud UserDiscovery) Lookup(idBytes []byte, callback LookupCallback,
 		callback.Callback(c, errStr)
 	}
 
-	return ud.ud.Lookup(uid, cb, timeout)
+	// Retrieve user discovery contact object
+	udContact, err := ud.ud.GetContact()
+	if err != nil {
+		return 0, errors.WithMessage(err,
+			"Failed to get user discovery "+
+				"contact object")
+	}
+
+	rid, _, err := udPackage.Lookup(client.api.GetNetworkInterface(),
+		client.api.GetRng(), client.api.GetE2e().GetGroup(),
+		udContact,
+		cb, uid, timeout)
+
+	if err != nil {
+		return 0, errors.WithMessagef(err,
+			"Failed to lookup ID %q", uid)
+	}
+
+	return int(rid), nil
 
 }
 
@@ -277,7 +350,8 @@ type lookupResponse struct {
 // This will reject if that id is malformed or if the indexing on the IDList
 // object is wrong. The MultiLookupCallback will return with all contacts
 // returned within the timeout.
-func (ud UserDiscovery) MultiLookup(ids *IdList, callback MultiLookupCallback,
+func (ud UserDiscovery) MultiLookup(client *Client,
+	ids *IdList, callback MultiLookupCallback,
 	timeoutMS int) error {
 
 	idList := make([]*id.ID, 0, ids.Len())
@@ -301,6 +375,14 @@ func (ud UserDiscovery) MultiLookup(ids *IdList, callback MultiLookupCallback,
 
 	timeout := time.Duration(timeoutMS) * time.Millisecond
 
+	// Retrieve user discovery contact object
+	udContact, err := ud.ud.GetContact()
+	if err != nil {
+		return errors.WithMessage(err,
+			"Failed to get user discovery "+
+				"contact object")
+	}
+
 	//loop through the IDs and send the lookup
 	for i := range idList {
 		locali := i
@@ -315,7 +397,9 @@ func (ud UserDiscovery) MultiLookup(ids *IdList, callback MultiLookupCallback,
 		}
 
 		go func() {
-			err := ud.ud.Lookup(localID, cb, timeout)
+			_, _, err := udPackage.Lookup(client.api.GetNetworkInterface(),
+				client.api.GetRng(), client.api.GetE2e().GetGroup(),
+				udContact, cb, localID, timeout)
 			if err != nil {
 				results <- lookupResponse{
 					C: contact.Contact{},
@@ -366,7 +450,3 @@ func (ud *UserDiscovery) SetAlternativeUserDiscovery(address, cert, contactFile
 func (ud *UserDiscovery) UnsetAlternativeUserDiscovery() error {
 	return ud.ud.UnsetAlternativeUserDiscovery()
 }
-
-func WrapUserDiscovery(ud *ud.Manager) *UserDiscovery {
-	return &UserDiscovery{ud: ud}
-}
-- 
GitLab