diff --git a/README.md b/README.md index cb6d69e09ad7aab6c7676b2aae8c310539d286b4..b7b0c4585e5bbc5c6d533c7db63579fde1928d32 100644 --- a/README.md +++ b/README.md @@ -140,20 +140,22 @@ Full usage of client can be found with `client --help`: ``` $ ./client --help +Runs a client for cMix anonymous communication platform + Usage: client [flags] client [command] Available Commands: - generate Generates version and dependency information for the Elixxir binary - getndf Download the network definition file from the network and print it. - group Group commands for cMix client - help Help about any command - init Initialize a user ID but do not connect to the network - proto Load client with a proto client JSON file. - single Send and respond to single-use messages. - ud Register for and search users using the xx network user discovery service. - version Print the version and dependency information for the Elixxir binary + fileTransfer Send and receive file for cMix client + generate Generates version and dependency information for the Elixxir binary + getndf Download the network definition file from the network and print it. + group Group commands for cMix client + help Help about any command + init Initialize a user ID but do not connect to the network + single Send and respond to single-use messages. + ud Register for and search users using the xx network user discovery service. + version Print the version and dependency information for the Elixxir binary Flags: --accept-channel Accept the channel request for the corresponding recipient ID @@ -173,8 +175,8 @@ Flags: -n, --ndf string Path to the network definition JSON file (default "ndf.json") -p, --password string Password to the session file --profile-cpu string Enable cpu profiling to this file - --protoUserOut string Path to which a normally constructed client will write proto user JSON file (default "protoUser.json") - --protoUserPath string Path to proto user JSON file containing cryptographic primitives the client will load (default "protoUser.json") + --protoUserOut string Path to which a normally constructed client will write proto user JSON file + --protoUserPath string Path to proto user JSON file containing cryptographic primitives the client will load --receiveCount uint How many messages we should wait for before quitting (default 1) --regcode string Identity code (optional) --send-auth-request Send an auth request to the specified destination and waitfor confirmation @@ -186,9 +188,9 @@ Flags: --unsafe Send raw, unsafe messages without e2e encryption. --unsafe-channel-creation Turns off the user identity authenticated channel check, automatically approving authenticated channels --verboseRoundTracking Verbose round tracking, keeps track and prints all rounds the client was aware of while running. Defaults to false if not set. + --verify-sends Ensure successful message sending by checking for round completion --waitTimeout uint The number of seconds to wait for messages to arrive (default 15) -w, --writeContact string Write contact information, if any, to this file, defaults to stdout (default "-") - file Use "client [command] --help" for more information about a command. ``` diff --git a/cmd/root.go b/cmd/root.go index a2c9db19265e702aec3c5d268185cd2156b3b8dd..35a24ac42149afc3085f0eae0924aa53fcd0ba33 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,7 +12,6 @@ import ( "encoding/base64" "encoding/binary" "encoding/hex" - "errors" "fmt" "github.com/spf13/cobra" jww "github.com/spf13/jwalterweatherman" @@ -198,35 +197,61 @@ var rootCmd = &cobra.Command{ go func(i int) { defer wg.Done() fmt.Printf("Sending to %s: %s\n", recipientID, msgBody) - var roundIDs []id.Round - var roundTimeout time.Duration - if unsafe { - roundIDs, err = client.SendUnsafe(msg, - paramsUnsafe) - roundTimeout = paramsUnsafe.Timeout - } else { - roundIDs, _, _, err = client.SendE2E(msg, - paramsE2E) - roundTimeout = paramsE2E.Timeout - } - if err != nil { - jww.FATAL.Panicf("%+v", err) - } - - // Construct the callback function which prints out the rounds' results - f := func(allRoundsSucceeded, timedOut bool, - rounds map[id.Round]api.RoundResult) { - printRoundResults(allRoundsSucceeded, timedOut, rounds, roundIDs, msg) - } - - // Have the client report back the round results - err = errors.New("derp") - for j := 0; j < 5 && err != nil; j++ { - err = client.GetRoundResults(roundIDs, roundTimeout, f) - } - - if err != nil { - jww.FATAL.Panicf("Message sending for send %d failed: %+v", i, err) + for { + // Send messages + var roundIDs []id.Round + var roundTimeout time.Duration + if unsafe { + roundIDs, err = client.SendUnsafe(msg, + paramsUnsafe) + roundTimeout = paramsUnsafe.Timeout + } else { + roundIDs, _, _, err = client.SendE2E(msg, + paramsE2E) + roundTimeout = paramsE2E.Timeout + } + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + + if viper.GetBool("verify-sends") { // Verify message sends were successful + retryChan := make(chan struct{}) + done := make(chan struct{}, 1) + + // Construct the callback function which + // verifies successful message send or retries + f := func(allRoundsSucceeded, timedOut bool, + rounds map[id.Round]api.RoundResult) { + printRoundResults(allRoundsSucceeded, timedOut, rounds, roundIDs, msg) + if !allRoundsSucceeded { + retryChan <- struct{}{} + } else { + done <- struct{}{} + } + } + + // Monitor rounds for results + err = client.GetRoundResults(roundIDs, roundTimeout, f) + if err != nil { + jww.DEBUG.Printf("Could not verify messages were sent successfully, resending messages...") + continue + } + + select { + case <-retryChan: + // On a retry, go to the top of the loop + jww.DEBUG.Printf("Messages were not sent successfully, resending messages...") + continue + case <-done: + // Close channels on verification success + close(done) + close(retryChan) + break + } + + } + + break } }(i) } @@ -842,6 +867,10 @@ func init() { "", 500, "The delay between sending the messages in ms") viper.BindPFlag("sendDelay", rootCmd.Flags().Lookup("sendDelay")) + rootCmd.Flags().BoolP("verify-sends", "", false, + "Ensure successful message sending by checking for round completion") + viper.BindPFlag("verify-sends", rootCmd.Flags().Lookup("verify-sends")) + rootCmd.Flags().UintP("receiveCount", "", 1, "How many messages we should wait for before quitting") viper.BindPFlag("receiveCount", rootCmd.Flags().Lookup("receiveCount"))