errors.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package module
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "net/http"
  8. "runtime"
  9. )
  10. // Err... are errors used globally
  11. var (
  12. ErrUnknown = errors.New("Unknown error")
  13. // ErrRetrievingImage = errors.New("Error retrieving image")
  14. // ErrInvalidURL = errors.New("Passed URL is not valid")
  15. // ErrDecodingImage = errors.New("Error decoding image")
  16. // ErrWidthNoInteger = errors.New("Error parsing width parameter as integer")
  17. // ErrHeightNoInteger = errors.New("Error parsing height parameter as integer")
  18. // ErrAspectRatioWidthNoInteger = errors.New("Error parsing aspect ratio width parameter as integer")
  19. // ErrAspectRatioHeightNoInteger = errors.New("Error parsing aspect ratio height parameter as integer")
  20. ErrReadingRequestBody = errors.New("Error reading request body")
  21. ErrDecodingJSON = errors.New("Error decoding JSON")
  22. // ErrDecodingBase64 = errors.New("Error decoding base64 encoded image")
  23. // ErrReadingCroppedImage = errors.New("Error reading cropped image")
  24. // ErrCreatingThumbnail = errors.New("Error creating thumbnail")
  25. // ErrDecodingImageInternal = errors.New("Error decoding image")
  26. // ErrEncodingImage = errors.New("Error encoding image")
  27. ErrSendingResponse = errors.New("Error sending response")
  28. ErrEncodingJSON = errors.New("Error encoding JSON")
  29. ErrDatabase = errors.New("Database error")
  30. ErrRetrievingTestData = errors.New("Error receiving Testdata")
  31. ErrParsingInt = errors.New("Error parsing string to int")
  32. ErrReadingFile = errors.New("Error reading file")
  33. )
  34. // StatusCodeMapper maps errors to HTTP Status codes
  35. var StatusCodeMapper = map[error]int{
  36. ErrUnknown: http.StatusInternalServerError,
  37. // ErrRetrievingImage: http.StatusBadRequest,
  38. // ErrInvalidURL: http.StatusBadRequest,
  39. // ErrDecodingImage: http.StatusBadRequest,
  40. // ErrWidthNoInteger: http.StatusBadRequest,
  41. // ErrHeightNoInteger: http.StatusBadRequest,
  42. // ErrAspectRatioWidthNoInteger: http.StatusBadRequest,
  43. // ErrAspectRatioHeightNoInteger: http.StatusBadRequest,
  44. ErrReadingRequestBody: http.StatusBadRequest,
  45. ErrDecodingJSON: http.StatusBadRequest,
  46. // ErrDecodingBase64: http.StatusBadRequest,
  47. // ErrReadingCroppedImage: http.StatusInternalServerError,
  48. // ErrCreatingThumbnail: http.StatusInternalServerError,
  49. // ErrDecodingImageInternal: http.StatusInternalServerError,
  50. // ErrEncodingImage: http.StatusInternalServerError,
  51. ErrSendingResponse: http.StatusInternalServerError,
  52. ErrEncodingJSON: http.StatusInternalServerError,
  53. ErrDatabase: http.StatusInternalServerError,
  54. ErrRetrievingTestData: http.StatusBadGateway,
  55. ErrParsingInt: http.StatusInternalServerError,
  56. ErrReadingFile: http.StatusInternalServerError,
  57. }
  58. // MetaError is two errors in one
  59. type MetaError struct {
  60. outerError error
  61. innerError error
  62. httpStatus int
  63. }
  64. // NewMetaError returns a new MetaError and automatically selects the suited HTTP Status Code
  65. func NewMetaError(outerError error, innerError error) MetaError {
  66. return MetaError{outerError, innerError, StatusCodeMapper[outerError]}
  67. }
  68. // NewMetaErrorWithStatus returns a new MetaError with manually selected HTTP Status Code
  69. func NewMetaErrorWithStatus(outerError error, innerError error, httpStatus int) MetaError {
  70. return MetaError{outerError, innerError, httpStatus}
  71. }
  72. func (err MetaError) Error() string {
  73. return err.outerError.Error() + ": " + err.innerError.Error()
  74. }
  75. type StatusError struct {
  76. error
  77. httpStatus int
  78. }
  79. func NewStatusError(err error, status int) StatusError {
  80. return StatusError{err, status}
  81. }
  82. // HandleError will handle errors
  83. func HandleError(outerErr error, innerErr error) {
  84. if innerErr != nil {
  85. switch outerErr {
  86. case ErrDatabase:
  87. switch innerErr.Error() {
  88. case "record not found":
  89. panic(NewStatusError(innerErr, http.StatusNotFound))
  90. }
  91. }
  92. panic(NewMetaError(outerErr, innerErr))
  93. }
  94. }
  95. // HTTPStatusHandler ...
  96. type HTTPStatusHandler struct {
  97. Debug bool // TODO implement
  98. }
  99. // NewHTTPStatusHandler ...
  100. func NewHTTPStatusHandler() *HTTPStatusHandler {
  101. return &HTTPStatusHandler{
  102. Debug: false,
  103. }
  104. }
  105. // HTTPStatusRecovery catches errors and serves http statuses
  106. func (rec *HTTPStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  107. defer func() {
  108. if err := recover(); err != nil {
  109. // get the stack traces and print it out
  110. // stack := stack(0)
  111. // log.Printf("PANIC: %s\n%s", err, stack)
  112. // convert err to a string
  113. var errMsg string
  114. if e, ok := err.(error); ok {
  115. errMsg = e.Error()
  116. } else {
  117. errMsg = fmt.Sprint(err)
  118. }
  119. // Logging
  120. _, file, line, _ := runtime.Caller(4)
  121. log.Printf("%s:%d: %s", file, line, errMsg)
  122. errText, jErr := json.Marshal(map[string]string{"status": errMsg})
  123. if jErr != nil {
  124. log.Println(jErr)
  125. // TODO handle error
  126. }
  127. if _, ok := err.(MetaError); ok {
  128. http.Error(w, string(errText), err.(MetaError).httpStatus)
  129. } else if _, ok = err.(StatusError); ok {
  130. http.Error(w, string(errText), err.(StatusError).httpStatus)
  131. } else {
  132. http.Error(w, string(errText), http.StatusInternalServerError)
  133. }
  134. }
  135. }()
  136. next(w, r)
  137. }
  138. // Log logs
  139. func Log(text string) {
  140. log.Println(text)
  141. }