//////////////////////////////////////////////////////////////////////////////// // Copyright © 2022 xx foundation // // // // Use of this source code is governed by a license that can be found in the // // LICENSE file. // //////////////////////////////////////////////////////////////////////////////// package bindings import ( "context" "encoding/json" "fmt" "github.com/pkg/errors" "strings" "sync" ) // 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{ // 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<Mux is a global lock for the errToUserErr global. var errorMux sync.RWMutex // Error codes const ( UnrecognizedCode = "UR: " UnrecognizedMessage = UnrecognizedCode + "Unrecognized error from XX backend, please report" ) // CreateUserFriendlyErrorMessage will convert the passed in error string to an // error string that is user-friendly if a substring match is found to a // common error. Common errors is a map that can be updated using // UpdateCommonErrors. 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. // // Parameters: // - errStr - an error returned from the backend. // // Returns // - A user-friendly error message. This should be devoid of technical speak // but still be meaningful for front-end or back-end teams. func CreateUserFriendlyErrorMessage(errStr string) string { errorMux.RLock() defer errorMux.RUnlock() // Go through common errors for backendErr, userFriendly := range errToUserErr { // Determine if error contains a common error if strings.Contains(errStr, backendErr) { return userFriendly } } descStr := "desc = " // If this contains an rpc error, determine how to handle it if strings.Contains(errStr, context.DeadlineExceeded.Error()) { // If there is a context deadline exceeded message, return the higher level // as context deadline exceeded is not informative rpcErr := "rpc " rpcIdx := strings.Index(errStr, rpcErr) return errStr[:rpcIdx] } else if strings.Contains(errStr, descStr) { // If containing an rpc error where context deadline exceeded // is NOT involved, the error returned server-side is often //more informative descIdx := strings.Index(errStr, descStr) // return everything after "desc = " return errStr[descIdx+len(descStr):] } // If a compound error message, return the highest level message errParts := strings.Split(errStr, ":") if len(errParts) > 1 { // Return everything before the first : return UnrecognizedCode + errParts[0] } return fmt.Sprintf("%s: %v", UnrecognizedCode, errStr) } // UpdateCommonErrors updates the internal error mapping database. This internal // database maps errors returned from the backend to user-friendly error // messages. // // Parameters: // - jsonFile - contents of a JSON file whose format conforms to the example below. // // Example Input: // { // "Failed to Unmarshal Conversation": "Could not retrieve conversation", // "Failed to unmarshal SentRequestMap": "Failed to pull up friend requests", // "cannot create username when network is not health": "Cannot create username, unable to connect to network", // } func UpdateCommonErrors(jsonFile string) error { errorMux.Lock() defer errorMux.Unlock() err := json.Unmarshal([]byte(jsonFile), &errToUserErr) if err != nil { return errors.WithMessage(err, "Failed to unmarshal json file, "+ "did you pass in the contents or the path?") } return nil }