diff --git a/bindings/client.go b/bindings/client.go index 09e0c7b6a6fc9ca4b643cf7cad645b7c466cd393..4abd7b17326ddce487d25d08f75955f112aaf8f3 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -41,9 +41,11 @@ func init() { // BindingsClient wraps the api.Client, implementing additional functions // to support the gomobile Client interface type Client struct { - api api.Client - single *single.Manager - singleMux sync.Mutex + api api.Client + single *single.Manager + singleMux sync.Mutex + errorMux sync.RWMutex + errToUserErr map[string]string } // NewClient creates client storage, generates keys, connects, and registers @@ -504,8 +506,8 @@ func (b *BindingsClient) Search(data, separator string, func (c *Client) getSingle() (*single.Manager, error) { c.singleMux.Lock() defer c.singleMux.Unlock() - if c.single==nil{ - if !c.IsNetworkHealthy(){ + if c.single == nil { + if !c.IsNetworkHealthy() { return nil, errors.New("cannot return single manager, network si not healthy") } apiClient := &c.api @@ -514,4 +516,4 @@ func (c *Client) getSingle() (*single.Manager, error) { } return c.single, nil -} \ No newline at end of file +} diff --git a/bindings/errors.go b/bindings/errors.go index 09ffcb8170f4877182e9152c9db54bc896a8b1fe..6268c3afd1ef576e94e1566669e2ee1efc8e785a 100644 --- a/bindings/errors.go +++ b/bindings/errors.go @@ -9,30 +9,32 @@ package bindings import ( "context" + "encoding/json" + "fmt" + "github.com/pkg/errors" "strings" ) // ErrToUserErr maps backend patterns to user friendly error messages. // Example format: // (Back-end) "Building new HostPool because no HostList stored:": (Front-end) "Missing host list", -var ErrToUserErr = map[string]string{ - // todo populate with common errors - // Registration errors - "cannot create username when network is not health" : - "Cannot create username, unable to connect to network", - "failed to add due to malformed fact stringified facts must at least have a type at the start" : - "Invalid fact, is the field empty?", - // UD failures - "failed to create user discovery manager: cannot return single manager, network is not health" : - "Could not connect to user discovery", - "user discovery returned error on search: no results found" : - "No results found", - "failed to search.: waiting for response to single-use transmisson timed out after 10s" : - "Search timed out", - "the phone number supplied was empty" : "Invalid phone number", - "failed to create user discovery manager: cannot start ud manager when network follower is not running." : - "Could not get network status", -} +//var ErrToUserErr = map[string]string{ +//// Registration errors +//"cannot create username when network is not health" : +// "Cannot create username, unable to connect to network", +//"failed to add due to malformed fact stringified facts must at least have a type at the start" : +// "Invalid fact, is the field empty?", +//// UD failures +//"failed to create user discovery manager: cannot return single manager, network is not health" : +// "Could not connect to user discovery", +//"user discovery returned error on search: no results found" : +// "No results found", +//"failed to search.: waiting for response to single-use transmisson timed out after 10s" : +// "Search timed out", +//"the phone number supplied was empty" : "Invalid phone number", +//"failed to create user discovery manager: cannot start ud manager when network follower is not running." : +// "Could not get network status", +//} // Error codes const UnrecognizedCode = "UR: " @@ -45,9 +47,11 @@ const UnrecognizedMessage = UnrecognizedCode + "Unrecognized error from XX backe // ErrToUserErr to provide a more user-friendly error message for the front end. // If the error is not common, some simple parsing is done on the error message // to make it more user-accessible, removing backend specific jargon. -func ErrorStringToUserFriendlyMessage(errStr string) string { +func (c *Client) ErrorStringToUserFriendlyMessage(errStr string) string { + c.errorMux.RLock() + defer c.errorMux.RUnlock() // Go through common errors - for backendErr, userFriendly := range ErrToUserErr { + for backendErr, userFriendly := range c.errToUserErr { // Determine if error contains a common error if strings.Contains(errStr, backendErr) { return userFriendly @@ -68,7 +72,7 @@ func ErrorStringToUserFriendlyMessage(errStr string) string { //more informative descIdx := strings.Index(errStr, descStr) // return everything after "desc = " - return errStr[descIdx+len(descStr):] + return errStr[descIdx+len(descStr):] } // If a compound error message, return the highest level message @@ -78,5 +82,21 @@ func ErrorStringToUserFriendlyMessage(errStr string) string { return UnrecognizedCode + errParts[0] } - return UnrecognizedMessage + return fmt.Sprintf("%s: %v", UnrecognizedCode, errStr) +} + +// UpdateCommonErrors takes the passed in contents of a JSON file and updates the +// ErrToUserErr map with the contents of the json file. The JSON's expected format +// conform with the commented examples provides in ErrToUserErr above. +// NOTE that you should not pass in a file path, but a preloaded JSON file +func (c *Client) UpdateCommonErrors(jsonFile string) error { + c.errorMux.Lock() + defer c.errorMux.Unlock() + err := json.Unmarshal([]byte(jsonFile), &c.errToUserErr) + if err != nil { + return errors.WithMessage(err, "Failed to unmarshal json file, "+ + "did you pass in the contents or the path?") + } + + return nil } diff --git a/bindings/errors_test.go b/bindings/errors_test.go index 0004d2a5ce7bd262f5ff698b58b372a7a6f4e7ec..c232a14a361267891ae4f481981d20ffd737a6cc 100644 --- a/bindings/errors_test.go +++ b/bindings/errors_test.go @@ -21,12 +21,14 @@ func TestErrorStringToUserFriendlyMessage(t *testing.T) { userErrs := []string{"Could not retrieve conversation", "Failed to initiate group chat", "Failed to pull up friend requests"} + c := &Client{errToUserErr: make(map[string]string)} + for i, exampleErr := range backendErrs { - ErrToUserErr[exampleErr] = userErrs[i] + c.errToUserErr[exampleErr] = userErrs[i] } // Check if a mapped common error returns the expected user friendly error - received := ErrorStringToUserFriendlyMessage(backendErrs[0]) + received := c.ErrorStringToUserFriendlyMessage(backendErrs[0]) if strings.Compare(received, userErrs[0]) != 0 { t.Errorf("Unexpected user friendly message returned from common error mapping."+ "\n\tExpected: %s"+ @@ -38,7 +40,7 @@ func TestErrorStringToUserFriendlyMessage(t *testing.T) { expected := "Could not poll network: " rpcPrefix := "rpc error: desc = " rpcErr := expected + rpcPrefix + context.DeadlineExceeded.Error() - received = ErrorStringToUserFriendlyMessage(rpcErr) + received = c.ErrorStringToUserFriendlyMessage(rpcErr) if strings.Compare(expected, received) != 0 { t.Errorf("Rpc error parsed unxecpectedly with error "+ "\n\"%s\" "+ @@ -49,7 +51,7 @@ func TestErrorStringToUserFriendlyMessage(t *testing.T) { // Test RPC error where server side error information is provided serverSideError := "Could not parse message! Please try again with a properly crafted message" rpcErr = rpcPrefix + serverSideError - received = ErrorStringToUserFriendlyMessage(rpcErr) + received = c.ErrorStringToUserFriendlyMessage(rpcErr) if strings.Compare(serverSideError, received) != 0 { t.Errorf("RPC error parsed unexpectedly with error "+ "\n\"%s\" "+ @@ -60,7 +62,7 @@ func TestErrorStringToUserFriendlyMessage(t *testing.T) { // Test uncommon error, should return highest level message expected = "failed to register with permissioning" uncommonErr := expected + ": sendRegistrationMessage: Unable to contact Identity Server" - received = ErrorStringToUserFriendlyMessage(uncommonErr) + received = c.ErrorStringToUserFriendlyMessage(uncommonErr) if strings.Compare(received, UnrecognizedCode+expected) != 0 { t.Errorf("Uncommon error parsed unexpectedly with error "+ "\n\"%s\" "+ @@ -71,8 +73,8 @@ func TestErrorStringToUserFriendlyMessage(t *testing.T) { // Test fully unrecognizable and un-parsable message, // should hardcoded error message uncommonErr = "failed to register with permissioning" - received = ErrorStringToUserFriendlyMessage(uncommonErr) - if strings.Compare(UnrecognizedMessage, received) != 0 { + received = c.ErrorStringToUserFriendlyMessage(uncommonErr) + if strings.Compare(UnrecognizedCode+": "+uncommonErr, received) != 0 { t.Errorf("Uncommon error parsed unexpectedly with error "+ "\n\"%s\" "+ "\n\tExpected: %s"+ @@ -80,3 +82,29 @@ func TestErrorStringToUserFriendlyMessage(t *testing.T) { } } + +// Unit test +func TestClient_UpdateCommonErrors(t *testing.T) { + c := &Client{errToUserErr: make(map[string]string)} + + key, expectedVal := "failed to create group key preimage", "Failed to initiate group chat" + + jsonData := "{\"Failed to Unmarshal Conversation\":\"Could not retrieve conversation\",\"Failed to unmarshal SentRequestMap\":\"Failed to pull up friend requests\",\"failed to create group key preimage\":\"Failed to initiate group chat\"}\n" + + err := c.UpdateCommonErrors(jsonData) + if err != nil { + t.Fatalf("UpdateCommonErrors error: %v", err) + } + + val, ok := c.errToUserErr[key] + if !ok { + t.Fatalf("Expected entry was not populated") + } + + if strings.Compare(expectedVal, val) != 0 { + t.Fatalf("Entry in updated error map was not expected."+ + "\n\tExpected: %s"+ + "\n\tReceived: %s", expectedVal, val) + } + +}