From 8ea3571729e08c78d579c2dbca42dce7cea920d7 Mon Sep 17 00:00:00 2001
From: "Richard T. Carback III" <rick.carback@gmail.com>
Date: Wed, 2 Mar 2022 19:17:42 +0000
Subject: [PATCH] Move restore contacts core functions into it's own package.
 Remove any references to bindings in cmd/ and the new package.

---
 bindings/restoreContacts.go   |  81 ++++++++++++++++++++++++
 cmd/ud.go                     |  16 ++---
 interfaces/restoreContacts.go |  19 ++++++
 xxmutils/restoreContacts.go   | 112 +++++++++-------------------------
 4 files changed, 134 insertions(+), 94 deletions(-)
 create mode 100644 bindings/restoreContacts.go
 create mode 100644 interfaces/restoreContacts.go

diff --git a/bindings/restoreContacts.go b/bindings/restoreContacts.go
new file mode 100644
index 000000000..f9e796aff
--- /dev/null
+++ b/bindings/restoreContacts.go
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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
+
+import (
+	"gitlab.com/elixxir/client/interfaces"
+	"gitlab.com/elixxir/client/xxmutils"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// RestoreContactsUpdater interface provides a callback function
+// for receiving update information from RestoreContactsFromBackup.
+type RestoreContactsUpdater interface {
+	// RestoreContactsCallback is called to report the current # of contacts
+	// that have been found and how many have been restored
+	// against the total number that need to be
+	// processed. If an error occurs it it set on the err variable as a
+	// plain string.
+	RestoreContactsCallback(numFound, numRestored, total int, err string)
+}
+
+// RestoreContactsReport is a gomobile friendly report structure
+// for determining which IDs restored, which failed, and why.
+type RestoreContactsReport struct {
+	restored []*id.ID
+	failed   []*id.ID
+	errs     []error
+}
+
+// LenRestored returns the length of ID's restored.
+func (r *RestoreContactsReport) LenRestored() int {
+	return len(r.restored)
+}
+
+// LenFailed returns the length of the ID's failed.
+func (r *RestoreContactsReport) LenFailed() int {
+	return len(r.failed)
+}
+
+// GetRestoredAt returns the restored ID at index
+func (r *RestoreContactsReport) GetRestoredAt(index int) []byte {
+	return r.restored[index].Bytes()
+}
+
+// GetFailedAt returns the failed ID at index
+func (r *RestoreContactsReport) GetFailedAt(index int) []byte {
+	return r.failed[index].Bytes()
+}
+
+// GetErrorAt returns the error string at index
+func (r *RestoreContactsReport) GetErrorAt(index int) string {
+	return r.errs[index].Error()
+}
+
+// RestoreContactsFromBackup takes as input the jason output of the
+// `NewClientFromBackup` function, unmarshals it into IDs, looks up
+// each ID in user discovery, and initiates a session reset request.
+// This function will not return until every id in the list has been sent a
+// request. It should be called again and again until it completes.
+// xxDK users should not use this function. This function is used by
+// the mobile phone apps and are not intended to be part of the xxDK. It
+// should be treated as internal functions specific to the phone apps.
+func RestoreContactsFromBackup(backupPartnerIDs []byte, client *Client,
+	udManager *UserDiscovery, updatesCb interfaces.RestoreContactsUpdater) (
+	*RestoreContactsReport, error) {
+
+	restored, failed, errs, err := xxmutils.RestoreContactsFromBackup(
+		backupPartnerIDs, &client.api, udManager.ud, updatesCb)
+
+	return &RestoreContactsReport{
+		restored: restored,
+		failed:   failed,
+		errs:     errs,
+	}, err
+
+}
diff --git a/cmd/ud.go b/cmd/ud.go
index 38857421c..dc940811b 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -15,15 +15,13 @@ import (
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
-	"gitlab.com/elixxir/client/bindings"
-	"gitlab.com/elixxir/client/bindings/xxmutils"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/single"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/client/ud"
+	"gitlab.com/elixxir/client/xxmutils"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/primitives/fact"
-	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/utils"
 )
 
@@ -170,17 +168,13 @@ var udCmd = &cobra.Command{
 					err.Error())
 				jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err)
 			}
-			bindingsClient := bindings.WrapAPIClient(client)
-			bindingsUdMgr := bindings.WrapUserDiscovery(
-				userDiscoveryMgr)
-			report, err := xxmutils.RestoreContactsFromBackup(
-				idListFile, bindingsClient, bindingsUdMgr, nil)
+			restored, _, _, err := xxmutils.RestoreContactsFromBackup(
+				idListFile, client, userDiscoveryMgr, nil)
 			if err != nil {
 				jww.FATAL.Panicf("%+v", err)
 			}
-			for i := 0; i < report.LenRestored(); i++ {
-				idBytes := report.GetRestoredAt(i)
-				uid, _ := id.Unmarshal(idBytes)
+			for i := 0; i < len(restored); i++ {
+				uid := restored[i]
 				for !client.HasAuthenticatedChannel(uid) {
 					time.Sleep(time.Second)
 				}
diff --git a/interfaces/restoreContacts.go b/interfaces/restoreContacts.go
new file mode 100644
index 000000000..defc6877b
--- /dev/null
+++ b/interfaces/restoreContacts.go
@@ -0,0 +1,19 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package interfaces
+
+// RestoreContactsUpdater interface provides a callback function
+// for receiving update information from RestoreContactsFromBackup.
+type RestoreContactsUpdater interface {
+	// RestoreContactsCallback is called to report the current # of contacts
+	// that have been found and how many have been restored
+	// against the total number that need to be
+	// processed. If an error occurs it it set on the err variable as a
+	// plain string.
+	RestoreContactsCallback(numFound, numRestored, total int, err string)
+}
diff --git a/xxmutils/restoreContacts.go b/xxmutils/restoreContacts.go
index 7653089d8..6bced7e15 100644
--- a/xxmutils/restoreContacts.go
+++ b/xxmutils/restoreContacts.go
@@ -19,57 +19,14 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 
 	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/bindings"
+	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/client/ud"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/id"
 )
 
-// RestoreContactsUpdater interface provides a callback function
-// for receiving update information from RestoreContactsFromBackup.
-type RestoreContactsUpdater interface {
-	// RestoreContactsCallback is called to report the current # of contacts
-	// that have been found and how many have been restored
-	// against the total number that need to be
-	// processed. If an error occurs it it set on the err variable as a
-	// plain string.
-	RestoreContactsCallback(numFound, numRestored, total int, err string)
-}
-
-// RestoreContactsReport is a gomobile friendly report structure
-// for determining which IDs restored, which failed, and why.
-type RestoreContactsReport struct {
-	restored []*id.ID
-	failed   []*id.ID
-	errs     []error
-}
-
-// LenRestored returns the length of ID's restored.
-func (r *RestoreContactsReport) LenRestored() int {
-	return len(r.restored)
-}
-
-// LenFailed returns the length of the ID's failed.
-func (r *RestoreContactsReport) LenFailed() int {
-	return len(r.failed)
-}
-
-// GetRestoredAt returns the restored ID at index
-func (r *RestoreContactsReport) GetRestoredAt(index int) []byte {
-	return r.restored[index].Bytes()
-}
-
-// GetFailedAt returns the failed ID at index
-func (r *RestoreContactsReport) GetFailedAt(index int) []byte {
-	return r.failed[index].Bytes()
-}
-
-// GetErrorAt returns the error string at index
-func (r *RestoreContactsReport) GetErrorAt(index int) string {
-	return r.errs[index].Error()
-}
-
 // RestoreContactsFromBackup takes as input the jason output of the
 // `NewClientFromBackup` function, unmarshals it into IDs, looks up
 // each ID in user discovery, and initiates a session reset request.
@@ -78,9 +35,13 @@ func (r *RestoreContactsReport) GetErrorAt(index int) string {
 // xxDK users should not use this function. This function is used by
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
-func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
-	udManager *bindings.UserDiscovery,
-	updatesCb RestoreContactsUpdater) (*RestoreContactsReport, error) {
+func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
+	udManager *ud.Manager,
+	updatesCb interfaces.RestoreContactsUpdater) ([]*id.ID, []*id.ID,
+	[]error, error) {
+
+	var restored, failed []*id.ID
+	var errs []error
 
 	// Constants/control settings
 	numRoutines := 8
@@ -94,16 +55,14 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 		}
 	}
 
-	api := client.GetInternalClient()
-
 	store := stateStore{
-		apiStore: api.GetStorage(),
+		apiStore: client.GetStorage(),
 	}
 
 	// Unmarshal IDs and then check restore state
 	var idList []*id.ID
 	if err := json.Unmarshal(backupPartnerIDs, &idList); err != nil {
-		return nil, err
+		return nil, nil, nil, err
 	}
 	lookupIDs, resetContacts, restored := checkRestoreState(idList, store)
 
@@ -112,11 +71,6 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 	totalCnt := len(idList)
 	lookupCnt := len(resetContacts)
 	resetCnt := totalCnt - len(resetContacts) - len(lookupIDs)
-	report := &RestoreContactsReport{
-		restored: restored,
-		failed:   make([]*id.ID, 0),
-		errs:     make([]error, 0),
-	}
 
 	// Before we start, report initial state
 	update(lookupCnt, resetCnt, totalCnt, "")
@@ -139,7 +93,8 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 	rsWg.Add(numRoutines)
 	for i := 0; i < numRoutines; i++ {
 		go LookupContacts(lookupCh, foundCh, failCh, udManager, lcWg)
-		go ResetSessions(resetContactCh, restoredCh, failCh, api, rsWg)
+		go ResetSessions(resetContactCh, restoredCh, failCh, *client,
+			rsWg)
 	}
 
 	// Load channels based on previous state
@@ -162,14 +117,14 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 	go func() {
 		defer failWg.Done()
 		for fail := range failCh {
-			report.failed = append(report.failed, fail.ID)
-			report.errs = append(report.errs, fail.Err)
+			failed = append(failed, fail.ID)
+			errs = append(errs, fail.Err)
 		}
 	}()
 
 	// Event Processing
 	done := false
-	var err error
+	var err error = nil
 	for !done {
 		// NOTE: Timer is reset every loop
 		timeoutTimer := time.NewTimer(restoreTimeout)
@@ -184,7 +139,7 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 			go func() { resetContactCh <- c }()
 		case c := <-restoredCh:
 			store.set(c, contactRestored)
-			report.restored = append(report.restored, c.ID)
+			restored = append(restored, c.ID)
 			resetCnt += 1
 		}
 		if resetCnt == totalCnt {
@@ -204,7 +159,7 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 	close(restoredCh)
 	failWg.Wait()
 
-	return report, err
+	return restored, failed, errs, err
 }
 
 // LookupContacts routine looks up contacts
@@ -212,7 +167,7 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *bindings.Client,
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
 func LookupContacts(in chan *id.ID, out chan *contact.Contact,
-	failCh chan failure, udManager *bindings.UserDiscovery,
+	failCh chan failure, udManager *ud.Manager,
 	wg sync.WaitGroup) {
 	defer wg.Done()
 	// Start looking up contacts with user discovery and feed this
@@ -241,12 +196,12 @@ func LookupContacts(in chan *id.ID, out chan *contact.Contact,
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
 func ResetSessions(in, out chan *contact.Contact, failCh chan failure,
-	api api.Client, wg sync.WaitGroup) {
+	client api.Client, wg sync.WaitGroup) {
 	defer wg.Done()
-	me := api.GetUser().GetContact()
+	me := client.GetUser().GetContact()
 	msg := "Account reset from backup"
 	for c := range in {
-		_, err := api.ResetSession(*c, me, msg)
+		_, err := client.ResetSession(*c, me, msg)
 		if err == nil {
 			out <- c
 			continue
@@ -262,28 +217,27 @@ func ResetSessions(in, out chan *contact.Contact, failCh chan failure,
 // xxDK users should not use this function. This function is used by
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
-func LookupContact(userID *id.ID, udManager *bindings.UserDiscovery) (
+func LookupContact(userID *id.ID, udManager *ud.Manager) (
 	*contact.Contact, error) {
 	// This is a little wonky, but wait until we get called then
 	// set the result to the contact objects details if there is
 	// no error
-	lookup := &lookupcb{}
 	waiter := sync.Mutex{}
 	var result *contact.Contact
 	var err error
-	lookup.CB = func(c *bindings.Contact, errStr string) {
+	lookupCB := func(c contact.Contact, myErr error) {
 		defer waiter.Unlock()
-		if errStr != "" {
-			err = errors.New(errStr)
+		if myErr != nil {
+			err = myErr
 		}
-		result = c.GetAPIContact()
+		result = &c
 	}
 	// Take lock once to make sure I will wait
 	waiter.Lock()
 
 	// in MS, so 90 seconds
-	timeout := 90 * 1000
-	udManager.Lookup(userID[:], lookup, timeout)
+	timeout := time.Duration(90 * time.Second)
+	udManager.Lookup(userID, lookupCB, timeout)
 
 	// Now force a wait for callback to exit
 	waiter.Lock()
@@ -292,14 +246,6 @@ func LookupContact(userID *id.ID, udManager *bindings.UserDiscovery) (
 	return result, err
 }
 
-// lookupcb provides the callback interface for UserDiscovery lookup function.
-type lookupcb struct {
-	CB func(c *bindings.Contact, err string)
-}
-
-// Callback implements desired interface
-func (l *lookupcb) Callback(c *bindings.Contact, err string) { l.CB(c, err) }
-
 // restoreState is the internal state of a contact
 type restoreState byte
 
-- 
GitLab