From 5a8471b3c4981df24356fc04715cff6457e578c7 Mon Sep 17 00:00:00 2001
From: "Richard T. Carback III" <rick.carback@gmail.com>
Date: Thu, 31 Dec 2020 02:46:02 +0000
Subject: [PATCH] UDB CLI first pass

---
 cmd/root.go |  79 +++++++++++++------------
 cmd/ud.go   | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 cmd/udb.go  |  56 ------------------
 3 files changed, 206 insertions(+), 94 deletions(-)
 delete mode 100644 cmd/udb.go

diff --git a/cmd/root.go b/cmd/root.go
index f226c6ebd..439cf5a7c 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -21,7 +21,7 @@ import (
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/switchboard"
-	"gitlab.com/xx_network/primitives/id"
+	w "gitlab.com/xx_network/primitives/id"
 	"io/ioutil"
 	"os"
 	"strconv"
@@ -45,41 +45,8 @@ var rootCmd = &cobra.Command{
 	Short: "Runs a client for cMix anonymous communication platform",
 	Args:  cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
-		initLog(viper.GetBool("verbose"), viper.GetString("log"))
-		jww.INFO.Printf(Version())
-
-		pass := viper.GetString("password")
-		storeDir := viper.GetString("session")
-		regCode := viper.GetString("regcode")
-		precannedID := viper.GetUint("sendid")
-
-		//create a new client if none exist
-		if _, err := os.Stat(storeDir); os.IsNotExist(err) {
-			// Load NDF
-			ndfPath := viper.GetString("ndf")
-			ndfJSON, err := ioutil.ReadFile(ndfPath)
-			if err != nil {
-				jww.FATAL.Panicf(err.Error())
-			}
-
-			if precannedID != 0 {
-				err = api.NewPrecannedClient(precannedID,
-					string(ndfJSON), storeDir, []byte(pass))
-			} else {
-				err = api.NewClient(string(ndfJSON), storeDir,
-					[]byte(pass), regCode)
-			}
-
-			if err != nil {
-				jww.FATAL.Panicf("%+v", err)
-			}
-		}
 
-		//load the client
-		client, err := api.Login(storeDir, []byte(pass))
-		if err != nil {
-			jww.FATAL.Panicf("%+v", err)
-		}
+		client := initClient()
 
 		user := client.GetUser()
 		jww.INFO.Printf("User: %s", user.ID)
@@ -110,7 +77,7 @@ var rootCmd = &cobra.Command{
 			})
 		}
 
-		err = client.StartNetworkFollower()
+		err := client.StartNetworkFollower()
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
 		}
@@ -214,6 +181,46 @@ var rootCmd = &cobra.Command{
 	},
 }
 
+func initClient() *api.Client {
+	initLog(viper.GetBool("verbose"), viper.GetString("log"))
+	jww.INFO.Printf(Version())
+
+	pass := viper.GetString("password")
+	storeDir := viper.GetString("session")
+	regCode := viper.GetString("regcode")
+	precannedID := viper.GetUint("sendid")
+
+	//create a new client if none exist
+	if _, err := os.Stat(storeDir); os.IsNotExist(err) {
+		// Load NDF
+		ndfPath := viper.GetString("ndf")
+		ndfJSON, err := ioutil.ReadFile(ndfPath)
+		if err != nil {
+			jww.FATAL.Panicf(err.Error())
+		}
+
+		if precannedID != 0 {
+			err = api.NewPrecannedClient(precannedID,
+				string(ndfJSON), storeDir, []byte(pass))
+		} else {
+			err = api.NewClient(string(ndfJSON), storeDir,
+				[]byte(pass), regCode)
+		}
+
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+	}
+
+	//load the client
+	client, err := api.Login(storeDir, []byte(pass))
+	if err != nil {
+		jww.FATAL.Panicf("%+v", err)
+	}
+
+	return client
+}
+
 func writeContact(c contact.Contact) {
 	outfilePath := viper.GetString("writeContact")
 	if outfilePath == "" {
diff --git a/cmd/ud.go b/cmd/ud.go
index 212396aa7..f35a44af6 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -12,6 +12,11 @@ import (
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
+	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/switchboard"
+	"gitlab.com/elixxir/client/ud"
+	"gitlab.com/elixxir/primitives/fact"
 )
 
 // udCmd user discovery subcommand, allowing user lookup and registration for
@@ -25,8 +30,161 @@ var udCmd = &cobra.Command{
 		"service"),
 	Args: cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
-		// UD Command does nothing right now.
-		jww.INFO.Printf("Hello, World")
+		client := initClient()
+		user := client.GetUser()
+		jww.INFO.Printf("User: %s", user.ID)
+		writeContact(user.GetContact())
+
+		userDiscoveryMgr, err := ud.NewManager(client)
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+
+		// Set up reception handler
+		swboard := client.GetSwitchboard()
+		recvCh := make(chan message.Receive, 10000)
+		listenerID := swboard.RegisterChannel("DefaultCLIReceiver",
+			switchboard.AnyUser(), message.Text, recvCh)
+		jww.INFO.Printf("Message ListenerID: %v", listenerID)
+
+		// Set up auth request handler, which simply prints the
+		// user id of the requestor.
+		authMgr := client.GetAuthRegistrar()
+		authMgr.AddGeneralRequestCallback(printChanRequest)
+
+		// If unsafe channels, add auto-acceptor
+		if viper.GetBool("unsafe-channel-creation") {
+			authMgr.AddGeneralRequestCallback(func(
+				requestor contact.Contact, message string) {
+				jww.INFO.Printf("Got Request: %s", requestor.ID)
+				err := client.ConfirmAuthenticatedChannel(
+					requestor)
+				if err != nil {
+					jww.FATAL.Panicf("%+v", err)
+				}
+			})
+		}
+
+		err := client.StartNetworkFollower()
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+
+		// Wait until connected or crash on timeout
+		connected := make(chan bool, 10)
+		client.GetHealth().AddChannel(connected)
+		waitUntilConnected(connected)
+
+		userToRegister := viper.GetString("register")
+		if userToRegister != "" {
+			err = userDiscoveryMgr.Register(userToRegister)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+		}
+
+		var facts []fact.Fact
+		phone := viper.GetString("addphone")
+		if phone != "" {
+			f, err := fact.NewFact(fact.Phone, phone)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			facts = append(facts, f)
+		}
+		email := viper.GetString("addemail")
+		if email != "" {
+			f, err := fact.NewFact(fact.Email, email)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			facts = append(facts, f)
+		}
+
+		for i := 0; i < len(facts); i++ {
+			r, err := userDiscoveryMgr.SendRegisterFact(facts[i])
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			// TODO Store the code
+
+			fmt.Printf("Fact Add Response: %+v", r)
+		}
+
+		confirmID := viper.GetString("confirm")
+		if confirmID != "" {
+			// TODO Lookup code
+			err = userDiscoveryMgr.SendConfirmFact(confirmID,
+				confirmID)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+		}
+
+		lookupIDStr := viper.GetString("lookup")
+		if lookupIDStr != "" {
+			lookupID, ok := parseRecipient(lookupIDStr)
+			if !ok {
+				jww.FATAL.Panicf("Could not parse: %s",
+					lookupIDStr)
+			}
+			userDiscoveryMgr.Lookup(lookupID,
+				func(newContact contact.Contact, err Error) {
+					if err != nil {
+						jww.FATAL.Panicf("%+v", err)
+					}
+					fmt.Printf(newContact.String())
+				},
+				time.Duration(10*time.Second))
+			time.Sleep(11 * time.Second)
+		}
+
+		usernameSrchStr := viper.GetString("searchusername")
+		emailSrchStr := viper.GetSTring("searchemail")
+		phoneSrchStr := viper.GetSTring("searchphone")
+
+		var facts FactList
+		if usernameSrchStr != "" {
+			f, err := fact.NewFact(fact.Username, usernameSrchStr)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			facts = append(facts, f)
+		}
+		if emailSrchStr != "" {
+			f, err := fact.NewFact(fact.Email, emailSrchStr)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			facts = append(facts, f)
+		}
+		if phoneSrchStr != "" {
+			f, err := fact.NewFact(fact.Phone, phoneSrchStr)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			facts = append(facts, f)
+		}
+
+		if len(facts) == 0 {
+			client.StopNetworkFollowers(10 * time.Second)
+			return
+		}
+
+		err := userDiscoveryMgr.Search(facts,
+			func(contacts []contact.Contact, err error) {
+				if err != nil {
+					jww.FATAL.Panicf("%+v", err)
+				}
+				for i := 0; i < len(contacts); i++ {
+					fmt.Printf(contacts[i].String())
+				}
+			}, 10*time.Second)
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
+		}
+		time.Sleep(11 * time.Second)
+		client.StopNetworkFollowers(10 * time.Second)
 	},
 }
 
@@ -42,6 +200,9 @@ func init() {
 	udCmd.Flags().StringP("addemail", "e", "",
 		"Add email to existing user registration.")
 	viper.BindPFlag("addemail", udCmd.Flags().Lookup("addemail"))
+	udCmd.Flags().StringP("confirm", "", "",
+		"Confirm fact with confirmation id")
+	viper.BindPFlag("confirm", udCmd.Flags().Lookup("confirm"))
 
 	udCmd.Flags().StringP("lookup", "u", "",
 		"Look up user ID. Use '0x' or 'b64:' for hex and base64 "+
diff --git a/cmd/udb.go b/cmd/udb.go
deleted file mode 100644
index 6f11250db..000000000
--- a/cmd/udb.go
+++ /dev/null
@@ -1,56 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package cmd
-
-import (
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/api"
-	"gitlab.com/xx_network/primitives/id"
-	"strings"
-	//"time"
-)
-
-type callbackSearch struct{}
-
-func (cs callbackSearch) Callback(userID, pubKey []byte, err error) {
-	if err != nil {
-		jww.INFO.Printf("UDB search failed: %v\n", err.Error())
-	} else if len(pubKey) == 0 {
-		jww.INFO.Printf("Public Key returned is empty\n")
-	} else {
-		userID, err := id.Unmarshal(userID)
-		if err != nil {
-			jww.ERROR.Printf("Malformed user ID from successful UDB search: %v", err)
-		}
-		jww.INFO.Printf("UDB search successful. Returned user %v\n",
-			userID)
-	}
-}
-
-var searchCallback = callbackSearch{}
-
-// Determines what UDB send function to call based on the text in the message
-func parseUdbMessage(msg string, client *api.Client) {
-	// Split the message on spaces
-	args := strings.Fields(msg)
-	if len(args) < 3 {
-		jww.ERROR.Printf("UDB command must have at least three arguments!")
-	}
-	// The first arg is the command
-	// the second is the valueType
-	// the third is the value
-	keyword := args[0]
-	// Case-insensitive match the keyword to a command
-	if strings.EqualFold(keyword, "SEARCH") {
-		//client.SearchForUser(args[2], searchCallback, 2*time.Minute)
-	} else if strings.EqualFold(keyword, "REGISTER") {
-		jww.ERROR.Printf("UDB REGISTER not allowed, it is already done during user registration")
-	} else {
-		jww.ERROR.Printf("UDB command not recognized!")
-	}
-}
-- 
GitLab