github.com/decred/politeia@v1.4.0/politeiawww/client/error.go (about) 1 // Copyright (c) 2020-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package client 6 7 import ( 8 "fmt" 9 "net/http" 10 "strings" 11 12 cmplugin "github.com/decred/politeia/politeiad/plugins/comments" 13 piplugin "github.com/decred/politeia/politeiad/plugins/pi" 14 tkplugin "github.com/decred/politeia/politeiad/plugins/ticketvote" 15 umplugin "github.com/decred/politeia/politeiad/plugins/usermd" 16 cmv1 "github.com/decred/politeia/politeiawww/api/comments/v1" 17 rcv1 "github.com/decred/politeia/politeiawww/api/records/v1" 18 tkv1 "github.com/decred/politeia/politeiawww/api/ticketvote/v1" 19 ) 20 21 // ErrorReply represents the request body that is returned from politeiawww 22 // when an error occurs. PluginID will only be populated if the error occurred 23 // during execution of a plugin command. 24 type ErrorReply struct { 25 PluginID string 26 ErrorCode int 27 ErrorContext string 28 } 29 30 // RespErr represents a politeiawww response error. A RespErr is returned 31 // anytime the politeiawww response is not a 200. 32 // 33 // The various politeiawww APIs can have overlapping error codes. The API is 34 // included to allow the Error() method to return the correct human readable 35 // error message. 36 type RespErr struct { 37 HTTPCode int 38 API string 39 ErrorReply ErrorReply 40 } 41 42 // Error satisfies the error interface. 43 func (e RespErr) Error() string { 44 switch e.HTTPCode { 45 case http.StatusInternalServerError: 46 return fmt.Sprintf("500 internal server error: %v", 47 e.ErrorReply.ErrorCode) 48 case http.StatusBadRequest: 49 var msg string 50 if e.ErrorReply.PluginID == "" { 51 // API user error 52 msg = apiUserErr(e.API, e.ErrorReply) 53 } else { 54 // Plugin user error 55 msg = pluginUserErr(e.ErrorReply) 56 } 57 return fmt.Sprintf("%v %v", e.HTTPCode, msg) 58 default: 59 return fmt.Sprintf("%v %+v", e.HTTPCode, e.ErrorReply) 60 } 61 } 62 63 func apiUserErr(api string, e ErrorReply) string { 64 var errMsg string 65 switch api { 66 case cmv1.APIRoute: 67 errMsg = cmv1.ErrorCodes[cmv1.ErrorCodeT(e.ErrorCode)] 68 case rcv1.APIRoute: 69 errMsg = rcv1.ErrorCodes[rcv1.ErrorCodeT(e.ErrorCode)] 70 case tkv1.APIRoute: 71 errMsg = tkv1.ErrorCodes[tkv1.ErrorCodeT(e.ErrorCode)] 72 } 73 74 // Remove "/" from api string. "/records/v1" to "records v1". 75 s := strings.Split(api, "/") 76 api = strings.Join(s, " ") 77 api = strings.Trim(api, " ") 78 79 // Create error string 80 m := fmt.Sprintf("%v user error code %v", api, e.ErrorCode) 81 if errMsg != "" { 82 m += fmt.Sprintf(", %v", errMsg) 83 } 84 if e.ErrorContext != "" { 85 m += fmt.Sprintf(": %v", e.ErrorContext) 86 } 87 return m 88 } 89 90 func pluginUserErr(e ErrorReply) string { 91 var errMsg string 92 switch e.PluginID { 93 case cmplugin.PluginID: 94 errMsg = cmplugin.ErrorCodes[cmplugin.ErrorCodeT(e.ErrorCode)] 95 case piplugin.PluginID: 96 errMsg = piplugin.ErrorCodes[piplugin.ErrorCodeT(e.ErrorCode)] 97 case tkplugin.PluginID: 98 errMsg = tkplugin.ErrorCodes[tkplugin.ErrorCodeT(e.ErrorCode)] 99 case umplugin.PluginID: 100 errMsg = umplugin.ErrorCodes[umplugin.ErrorCodeT(e.ErrorCode)] 101 } 102 m := fmt.Sprintf("%v plugin error code %v", e.PluginID, e.ErrorCode) 103 if errMsg != "" { 104 m += fmt.Sprintf(", %v", errMsg) 105 } 106 if e.ErrorContext != "" { 107 m += fmt.Sprintf(": %v", e.ErrorContext) 108 } 109 return m 110 }