package loggerdataresp import ( "io" "net" "net/http" "strings" "github.com/fiskerinc/cloud-services/pkg/common/staticerrors" er "github.com/fiskerinc/cloud-services/pkg/errors" e "github.com/fiskerinc/cloud-services/pkg/mongo/error" "github.com/fiskerinc/cloud-services/pkg/validator" "go.mongodb.org/mongo-driver/mongo" "github.com/fiskerinc/cloud-services/pkg/logger" "github.com/fiskerinc/cloud-services/pkg/utils" "github.com/go-pg/pg/v10" "github.com/pkg/errors" ) // Maybe if i move this out we will see all our problems solved var MongoUpdateErrorCheck = ErrorCheck{Err: e.ErrUnableToUpdate, Status: http.StatusNotFound} var MongoDeleteErrorCheck = ErrorCheck{Err: e.ErrUnableToDelete, Status: http.StatusNotFound} var PostgresNoRowsErrorCheck = ErrorCheck{Err: pg.ErrNoRows, Status: http.StatusNotFound} var EofErrorCheck = ErrorCheck{Err: io.EOF, Status: http.StatusNotFound} var CustomErrorCheck = ErrorCheck{} type ErrorCheck struct { Err error Status int } type respErr func(w http.ResponseWriter, status int, message string) // log an error message without populating an HTTP response func BadDataError(err error, options ...ErrorCheck) bool { return badDataErrorResp(nil, err, 0, nil, options) } // log an error message and populate an HTTP response func BadDataErrorResp(w http.ResponseWriter, err error, defaultStatus int, options ...ErrorCheck) bool { return badDataErrorResp(w, err, defaultStatus, utils.RespError, options) } // log an error message and populate an XML HTTP response func BadDataErrorXMLResp(w http.ResponseWriter, err error, defaultStatus int, options ...ErrorCheck) bool { return badDataErrorResp(w, err, defaultStatus, utils.RespXMLError, options) } // log an error message and populate an JSON RPC response func BadDataErrorJSONRPCResp(w http.ResponseWriter, errRPC error, err error) bool { if err == nil { return false } utils.RespJSONRPCError(w, errRPC, err.Error()) if errRPC == utils.ErrJSONRPCServerError || errRPC == utils.ErrJSONRPCInternalError { logger.Error().Err(err).Send() } else { logger.Warn().Err(err).Send() } return true } func badDataErrorResp(w http.ResponseWriter, err error, defaultStatus int, errFunc respErr, errorChecks []ErrorCheck) bool { if err == nil { return false } cause := errors.Cause(err) if ok, msg := validator.GetValidationErrorMsg(cause); ok { logError(err, msg, http.StatusBadRequest, errFunc, w) return true } if customErr, ok := cause.(*er.CustomError); ok { logError(customErr.Err(), customErr.Message, customErr.Status, errFunc, w) return true } for _, errorCheck := range errorChecks { if errors.Is(errorCheck.Err, cause) { logError(errorCheck.Err, errorCheck.Err.Error(), errorCheck.Status, errFunc, w) return true } } if handleMongoErrors(err, errFunc, w) { return true } if handlePgErrors(err, errFunc, w) { return true } if handleRedisErrors(err, errFunc, w) { return true } if handleSAPErrors(err, errFunc, w) { return true } logError(err, err.Error(), defaultStatus, errFunc, w) return true } func handleMongoErrors(err error, errFunc respErr, w http.ResponseWriter) bool { if mongo.IsDuplicateKeyError(err) { logError(err, err.Error(), http.StatusBadRequest, errFunc, w) return true } if mongo.IsTimeout(err) { logError(err, err.Error(), http.StatusServiceUnavailable, errFunc, w) return true } if mongo.IsNetworkError(err) { logError(err, err.Error(), http.StatusServiceUnavailable, errFunc, w) return true } return false } func handlePgErrors(err error, errFunc respErr, w http.ResponseWriter) bool { if pgErr, ok := err.(pg.Error); ok { switch pgErr.Field('V') { case "FATAL", "PANIC": logError(pgErr, pgErr.Error(), http.StatusServiceUnavailable, errFunc, w) return true } } return false } func handleRedisErrors(err error, errFunc respErr, w http.ResponseWriter) bool { if opError, ok := err.(*net.OpError); ok { logError(opError, opError.Error(), http.StatusServiceUnavailable, errFunc, w) return true } if dnsError, ok := err.(*net.DNSError); ok { logError(dnsError, dnsError.Error(), http.StatusServiceUnavailable, errFunc, w) return true } return false } func handleSAPErrors(err error, errFunc respErr, w http.ResponseWriter) bool { if strings.HasPrefix(err.Error(), staticerrors.ErrorSAPFailedCall) { logError(err, err.Error(), http.StatusServiceUnavailable, errFunc, w) return true } return false } func logError(err error, errMessage string, status int, errFunc respErr, w http.ResponseWriter) { switch status { case http.StatusServiceUnavailable, http.StatusInternalServerError: logger.Error().Err(err).Send() case http.StatusNotFound, http.StatusBadRequest, http.StatusForbidden: logger.Warn().Err(err).Send() default: logger.Warn().Err(err).Send() } if errFunc != nil && w != nil { errFunc(w, status, errMessage) } }