errs.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. package errs
  2. import (
  3. "fmt"
  4. "runtime"
  5. "github.com/davecgh/go-spew/spew"
  6. )
  7. type ErroNil *Error
  8. type Map map[string]interface{}
  9. type Error struct {
  10. HttpStatus int `json:"httpStatus"`
  11. CodeText string `json:"codetext"`
  12. Message string `json:"message"`
  13. Stack *ErrorStack `json:"stack,omitempty"`
  14. Errors []*Detail `json:"erros,omitempty"`
  15. }
  16. type Detail struct {
  17. Dominio string `json:"dominio,omitempty"`
  18. Reason string `json:"reason,omitempty"`
  19. Message string `json:"message,omitempty"`
  20. LocationType string `json:"locationType,omitempty"`
  21. Location string `json:"location,omitempty"`
  22. }
  23. type ErrorMapFunction func(error) (err *Error)
  24. // type ErrorMapFunction func(error) (err error, replaced bool)
  25. var (
  26. errorMapFunction = map[string]ErrorMapFunction{}
  27. )
  28. func RegisterMapErrorFunction(id string, fn ErrorMapFunction) {
  29. errorMapFunction[id] = fn
  30. }
  31. // Adiciona uma descricao ao erro
  32. // func (e *Erro) Add(desc *Detail) *Erro {
  33. // e.Errors = append(e.Errors, desc)
  34. // return e
  35. // }
  36. func (e *Error) Details(desc *Detail) *Error {
  37. e.Errors = append(e.Errors, desc)
  38. if len(e.Errors) == 1 {
  39. e.Message = desc.Message
  40. }
  41. return e
  42. }
  43. // Retorna a ultima descricao adicionada
  44. func (e *Error) LastDescription() *Detail {
  45. size := len(e.Errors)
  46. if size > 0 {
  47. return e.Errors[size-1]
  48. }
  49. return nil
  50. }
  51. // Error retorna a mensagem de erro principal
  52. func (e *Error) Error() string {
  53. reason := ""
  54. if len(e.Errors) > 0 {
  55. reason = e.LastDescription().Reason
  56. }
  57. return fmt.Sprintf("[%s] %s",reason, e.Message)
  58. }
  59. // The operation was cancelled, typically by the caller.
  60. //
  61. // HTTP Mapping: 499 Client Closed Request
  62. func Cancelled() *Error {
  63. return errorHandler(&Error{
  64. HttpStatus: 499,
  65. CodeText: "client_closed_request",
  66. Message: `Solicitação cancelada pelo cliente.`,
  67. })
  68. }
  69. // Unknown error. For example, this error may be returned when
  70. // a `Status` value received from another address space belongs to
  71. // an error space that is not known in this address space. Also
  72. // errors raised by APIs that do not return enough error information
  73. // may be converted to this error.
  74. //
  75. // HTTP Mapping: 500 Internal Server Error
  76. func Unknown() *Error {
  77. return errorHandler(&Error{
  78. HttpStatus: 500,
  79. CodeText: "internal_server_error",
  80. Message: "",
  81. })
  82. }
  83. // The client specified an invalid argument. Note that this differs
  84. // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments
  85. // that are problematic regardless of the state of the system
  86. // (e.g., a malformed file name).
  87. //
  88. // HTTP Mapping: 400 Bad Request
  89. func InvalidArgument() *Error {
  90. return errorHandler(&Error{
  91. HttpStatus: 400,
  92. CodeText: "bad_request",
  93. Message: "O campo de solicitação xyz é xxx, mas o esperado é [yyy, zzz].",
  94. })
  95. }
  96. // The deadline expired before the operation could complete. For operations
  97. // that change the state of the system, this error may be returned
  98. // even if the operation has completed successfully. For example, a
  99. // successful response from a server could have been delayed long
  100. // enough for the deadline to expire.
  101. //
  102. // HTTP Mapping: 504 Gateway Timeout
  103. func DeadlineExceeded() *Error {
  104. return errorHandler(&Error{
  105. HttpStatus: 504,
  106. CodeText: "gateway_timeout",
  107. Message: "",
  108. })
  109. }
  110. // Some requested entity (e.g., file or directory) was not found.
  111. //
  112. // Note to server developers: if a request is denied for an entire class
  113. // of users, such as gradual feature rollout or undocumented whitelist,
  114. // `NOT_FOUND` may be used. If a request is denied for some users within
  115. // a class of users, such as user-based access control, `PERMISSION_DENIED`
  116. // must be used.
  117. //
  118. // HTTP Mapping: 404 Not Found
  119. func NotFound() *Error {
  120. return errorHandler(&Error{
  121. HttpStatus: 404,
  122. CodeText: "not_found",
  123. Message: `O recurso "xxx" não foi encontrado.`,
  124. })
  125. }
  126. // The entity that a client attempted to create (e.g., file or directory)
  127. // already exists.
  128. //
  129. // HTTP Mapping: 409 Conflict
  130. func AlreadyExists() *Error {
  131. return errorHandler(&Error{
  132. HttpStatus: 409,
  133. CodeText: "conflict",
  134. Message: `O recurso já existe.`,
  135. })
  136. }
  137. // The caller does not have permission to execute the specified
  138. // operation. `PERMISSION_DENIED` must not be used for rejections
  139. // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
  140. // instead for those errors). `PERMISSION_DENIED` must not be
  141. // used if the caller can not be identified (use `UNAUTHENTICATED`
  142. // instead for those errors). This error code does not imply the
  143. // request is valid or the requested entity exists or satisfies
  144. // other pre-conditions.
  145. //
  146. // HTTP Mapping: 403 Forbidden
  147. func PermissionDenied() *Error {
  148. return errorHandler(&Error{
  149. HttpStatus: 403,
  150. CodeText: "forbidden",
  151. Message: `Permissão "xxx" negada no arquivo "yyy".`,
  152. })
  153. }
  154. // The request does not have valid authentication credentials for the
  155. // operation.
  156. //
  157. // HTTP Mapping: 401 Unauthorized
  158. func Unauthenticated() *Error {
  159. return errorHandler(&Error{
  160. HttpStatus: 401,
  161. CodeText: "unauthorized",
  162. Message: `Credenciais de autenticação inválidas.`,
  163. })
  164. }
  165. // Some resource has been exhausted, perhaps a per-user quota, or
  166. // perhaps the entire file system is out of space.
  167. //
  168. // HTTP Mapping: 429 Too Many Requests
  169. func ResourceExhausted() *Error {
  170. return errorHandler(&Error{
  171. HttpStatus: 429,
  172. CodeText: "too_many_requests",
  173. Message: `Limite de cota "xxx" excedido.`,
  174. })
  175. }
  176. // The operation was rejected because the system is not in a state
  177. // required for the operation's execution. For example, the directory
  178. // to be deleted is non-empty, an rmdir operation is applied to
  179. // a non-directory, etc.
  180. //
  181. // Service implementors can use the following guidelines to decide
  182. // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:
  183. // (a) Use `UNAVAILABLE` if the client can retry just the failing call.
  184. // (b) Use `ABORTED` if the client should retry at a higher level
  185. // (e.g., when a client-specified test-and-set fails, indicating the
  186. // client should restart a read-modify-write sequence).
  187. // (c) Use `FAILED_PRECONDITION` if the client should not retry until
  188. // the system state has been explicitly fixed. E.g., if an "rmdir"
  189. // fails because the directory is non-empty, `FAILED_PRECONDITION`
  190. // should be returned since the client should not retry unless
  191. // the files are deleted from the directory.
  192. //
  193. // HTTP Mapping: 400 Bad Request
  194. func FailedPrecondition() *Error {
  195. return errorHandler(&Error{
  196. HttpStatus: 400,
  197. CodeText: "bad_request",
  198. Message: `O recurso xxx é um diretório que não está vazio, portanto, não pode ser excluído.`,
  199. })
  200. }
  201. // The operation was aborted, typically due to a concurrency issue such as
  202. // a sequencer check failure or transaction abort.
  203. //
  204. // See the guidelines above for deciding between `FAILED_PRECONDITION`,
  205. // `ABORTED`, and `UNAVAILABLE`.
  206. //
  207. // HTTP Mapping: 409 Conflict
  208. func Aborted() *Error {
  209. return errorHandler(&Error{
  210. HttpStatus: 409,
  211. CodeText: "conflict",
  212. Message: `Não foi possível adquirir o bloqueio no recurso "xxx".`,
  213. })
  214. }
  215. // The operation was attempted past the valid range. E.g., seeking or
  216. // reading past end-of-file.
  217. //
  218. // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may
  219. // be fixed if the system state changes. For example, a 32-bit file
  220. // system will generate `INVALID_ARGUMENT` if asked to read at an
  221. // offset that is not in the range [0,2^32-1], but it will generate
  222. // `OUT_OF_RANGE` if asked to read from an offset past the current
  223. // file size.
  224. //
  225. // There is a fair bit of overlap between `FAILED_PRECONDITION` and
  226. // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific
  227. // error) when it applies so that callers who are iterating through
  228. // a space can easily look for an `OUT_OF_RANGE` error to detect when
  229. // they are done.
  230. //
  231. // HTTP Mapping: 400 Bad Request
  232. func OutOfRange() *Error {
  233. return errorHandler(&Error{
  234. HttpStatus: 400,
  235. CodeText: "bad_request",
  236. Message: `A "idade" do parâmetro está fora do intervalo [0, 125].`,
  237. })
  238. }
  239. func HTTPVersionNotSupported() *Error {
  240. return errorHandler(&Error{
  241. HttpStatus: 400,
  242. CodeText: "http_version_not_supported",
  243. Message: `The server doesn’t support the major HTTP version the client used to make the request.`,
  244. })
  245. }
  246. // The operation is not implemented or is not supported/enabled in this
  247. // service.
  248. //
  249. // HTTP Mapping: 501 Not Implemented
  250. func Unimplemented() *Error {
  251. return errorHandler(&Error{
  252. HttpStatus: 501,
  253. CodeText: "not_implemented",
  254. Message: `Método "xxx" não implementado.`,
  255. })
  256. }
  257. // Internal errors. This means that some invariants expected by the
  258. // underlying system have been broken. This error code is reserved
  259. // for serious errors.
  260. //
  261. // HTTP Mapping: 500 Internal Server Error
  262. func Internal() *Error {
  263. return errorHandler(&Error{
  264. HttpStatus: 500,
  265. CodeText: "internal_server_error",
  266. Message: `Error interno.`,
  267. })
  268. }
  269. // The service is currently unavailable. This is most likely a
  270. // transient condition, which can be corrected by retrying with
  271. // a backoff.
  272. //
  273. // See the guidelines above for deciding between `FAILED_PRECONDITION`,
  274. // `ABORTED`, and `UNAVAILABLE`.
  275. //
  276. // HTTP Mapping: 503 Service Unavailable
  277. func Unavaliable() *Error {
  278. return errorHandler(&Error{
  279. HttpStatus: 503,
  280. CodeText: "service_unavailable",
  281. Message: "Serviço indisponivel.",
  282. })
  283. }
  284. // Unrecoverable data loss or corruption.
  285. //
  286. // HTTP Mapping: 500 Internal Server Error
  287. func DataCaps() *Error {
  288. return errorHandler(&Error{
  289. HttpStatus: 500,
  290. CodeText: "internal_server_error",
  291. Message: `Error interno.`,
  292. })
  293. }
  294. func errorHandler(err *Error) *Error {
  295. err.Stack = Trace()
  296. return err
  297. }
  298. // }
  299. // func Error(code int, m string) *Error {
  300. // LogError(code, m)
  301. // e := ErrosList[code]
  302. // if m != "" {
  303. // e.Message = m
  304. // }
  305. // e.Details(&Detail{
  306. // Dominio: "global",
  307. // Message: m,
  308. // })
  309. // return &e
  310. // }
  311. // func FullError(code int, err *Detail) *Error {
  312. // // _, fn, line, _ := runtime.Caller(1
  313. // // LogError(code, fmt.Sprintf("%s:%d - %s", fn, line, err.Message))
  314. // e := ErrosList[code]
  315. // e.Message = err.Message
  316. // e.Stack = Trace()
  317. // e.Details(err)
  318. // return &e
  319. // }
  320. type ErrorStack struct {
  321. Frames []runtime.Frame
  322. }
  323. func (stack *ErrorStack) Print() {
  324. for _, f := range stack.Frames {
  325. fmt.Printf("%s\n\t%s:%d\n", f.Function, f.File, f.Line)
  326. }
  327. }
  328. func Trace() (stack *ErrorStack) {
  329. stack = &ErrorStack{}
  330. pc := make([]uintptr, 20)
  331. n := runtime.Callers(2, pc)
  332. if n == 0 {
  333. // No pcs available. Stop now.
  334. // This can happen if the first argument to runtime.Callers is large.
  335. return
  336. }
  337. pc = pc[:n] // pass only valid pcs to runtime.CallersFrames
  338. frames := runtime.CallersFrames(pc)
  339. // Loop to get frames.
  340. // A fixed number of pcs can expand to an indefinite number of Frames.
  341. for {
  342. frame, more := frames.Next()
  343. stack.Frames = append(stack.Frames, frame)
  344. // To keep this example's output stable
  345. // even if there are changes in the testing package,
  346. // stop unwinding when we leave package runtime.
  347. // if strings.Contains(frame.Function, "main.main") {
  348. // break
  349. // }
  350. // spew.Dump(frame)
  351. if !more {
  352. break
  353. }
  354. }
  355. return
  356. }
  357. func FromError(source error) (err *Error) {
  358. spew.Dump(source)
  359. for _, fn := range errorMapFunction {
  360. if err = fn(source); err != nil {
  361. return
  362. }
  363. }
  364. err = Internal().Details(&Detail{
  365. Message: source.Error(),
  366. })
  367. return
  368. }
  369. // 400 invalidParameter Indica que um parâmetro de solicitação tem um valor inválido. Os campos locationType e location na resposta de erro fornecem informações sobre qual valor era inválido. Não tente novamente sem corrigir o problema. Você precisa fornecer um valor válido para o parâmetro especificado na resposta de erro.
  370. // 400 badRequest Indica que a consulta era inválida. Por exemplo, o ID pai estava ausente ou a combinação de dimensões ou métricas solicitada não era válida. Não tente novamente sem corrigir o problema. Você precisa fazer alterações na consulta da API para que ela funcione.
  371. // 401 invalidCredentials Indica que o token de autenticação é inválido ou expirou. Não tente novamente sem corrigir o problema. Você precisa receber um novo token de autenticação.
  372. // 403 insufficientPermissions Indica que o usuário não tem permissões suficientes para a entidade especificada na consulta. Não tente novamente sem corrigir o problema. Você precisa receber permissões suficientes para executar a operação na entidade especificada.
  373. // 403 dailyLimitExceeded Indica que o usuário ultrapassou a cota diária [por projeto ou vista da propriedade (perfil)]. Não tente novamente sem corrigir o problema. Você esgotou sua cota diária. Consulte Limites e cotas da API.
  374. // 403 usageLimits.userRateLimitExceededUnreg Indica que o aplicativo precisa ser registrado no console de APIs do Google. Não tente novamente sem corrigir o problema. Você precisa se registrar no console de APIs para receber a cota completa da API.
  375. // 403 userRateLimitExceeded Indica que o limite da taxa de usuário foi ultrapassado. O limite de taxa máximo é de 10 qps por endereço IP. O valor padrão definido no console de APIs do Google é 1 qps por endereço IP. Você pode aumentar esse limite no console de APIs do Google para no máximo 10 qps. Tente novamente usando backoff exponencial. Você precisa diminuir a taxa em que envia as solicitações.
  376. // 403 rateLimitExceeded Indica que os limites de taxa global ou geral do projeto foram excedidos. Tente novamente usando backoff exponencial. Você precisa diminuir a taxa em que envia as solicitações.
  377. // 403 quotaExceeded Indica que o limite de 10 solicitações simultâneas por vista da propriedade (perfil) na API de relatórios principais foi atingido. Tente novamente usando backoff exponencial. Você precisa aguardar até que pelo menos uma solicitação em andamento para essa Vista (perfil) seja concluída.
  378. // ERR_BAD_REQUEST: Erro{
  379. // HttpStatus: 400,
  380. // CodeText: "bad_request",
  381. // Message: "",
  382. // },
  383. // ERR_INVALID_PARAM: Erro{
  384. // HttpStatus: 400,
  385. // CodeText: "invalid_param",
  386. // Message: "",
  387. // },
  388. // ERR_INVALID_PARAM_VALUE: Erro{
  389. // HttpStatus: 400,
  390. // CodeText: "invalid_param_value",
  391. // Message: "",
  392. // },
  393. // ERR_INVALID_CREDENTIAL: Erro{
  394. // HttpStatus: 401,
  395. // CodeText: "invalid_credential",
  396. // Message: "Invalid Credentials",
  397. // },
  398. // ERR_NOT_FOUND: Erro{
  399. // HttpStatus: 404,
  400. // CodeText: "not_found",
  401. // Message: "Recurso não existe",
  402. // },
  403. // ERR_PERSIST: Erro{
  404. // HttpStatus: 500,
  405. // CodeText: "persist_error",
  406. // Message: "Não foi possivel salvar as alterações",
  407. // },
  408. // ERR_CONFLICT: Erro{
  409. // HttpStatus: 409,
  410. // CodeText: "conflict",
  411. // Message: "A operação falhou porque o item é referenciado por outras.",
  412. // },
  413. // ERR_GENERAL: Erro{
  414. // HttpStatus: 500,
  415. // CodeText: "general",
  416. // Message: "Parece que algo deu errado. Nós pedimos desculpas. Você pode voltar para a página principal",
  417. // },
  418. // ERR_EXPIRED: Erro{
  419. // HttpStatus: 500,
  420. // CodeText: "expired",
  421. // Message: "Parece que o recurso não esta mais disponível",
  422. // },
  423. // const (
  424. // ERR_NOT_FOUND int = iota
  425. // ERR_GENERAL
  426. // ERR_PERSIST
  427. // ERR_INVALID_CREDENTIAL
  428. // ERR_BAD_REQUEST
  429. // ERR_INVALID_PARAM
  430. // ERR_INVALID_PARAM_VALUE
  431. // ERR_EXPIRED
  432. // ERR_NOT_MODIFIED
  433. // ERR_TEMPORARY_REDIRECT
  434. // ERR_UNAUTHORIZED
  435. // ERR_PAYMENT_REQUIRED
  436. // ERR_FORBIDDEN
  437. // ERR_METHOD_NOT_ALLOWED
  438. // ERR_CONFLICT
  439. // ERR_TOO_MANY_REQUESTS
  440. // ERR_NOT_IMPLEMENTED
  441. // ERR_SERVICE_UNAVAILABLE
  442. // )
  443. // Error cria uma instancia de um erro
  444. // code int assume:
  445. // ERR_NOT_FOUND int = 0
  446. // ERR_GENERAL int = 1
  447. // ERR_PERSIST int = 2
  448. // ERR_INVALID_CREDENTIAL int = 3
  449. // ERR_BAD_REQUEST int = 4
  450. // ERR_INVALID_PARAM int = 5
  451. // ERR_EXPIRED int = 6
  452. // func Errorf(code int, m string, args ...interface{}) *Erro {
  453. // LogError(code, m)
  454. // m = fmt.Sprintf(m, args...)
  455. // e := ErrosList[code]
  456. // if m != "" {
  457. // e.Message = m
  458. // }
  459. // e.Add(&Detail{
  460. // Dominio: "global",
  461. // Message: m,
  462. // })
  463. // return &e
  464. // }
  465. // func Falha(ctx context.Context, code int, m string, dev Map) {
  466. // // fmt.Println("CodeText:[", code, "]", m, dev);
  467. // // ctx.StopExecution()
  468. // base := ErrosList[code]
  469. // base.Development = Map{}
  470. // if m != "" {
  471. // base.Message = m
  472. // }
  473. // if dev != nil {
  474. // base.Development = dev
  475. // }
  476. // accept := ctx.GetHeader("Accept")
  477. // ctx.StatusCode(base.Code)
  478. // //spew.Dump(base)
  479. // if base.Error == "not_found" {
  480. // url := ctx.Host() + ctx.RequestPath(true)
  481. // base.Development["url"] = fmt.Sprintf("A url '%s' não foi encontrada.", url)
  482. // }
  483. // if accept == "application/json" {
  484. // ctx.JSON(base)
  485. // } else {
  486. // ctx.ViewData("", base)
  487. // // ctx.View(ViewScript(ctx, "error.html"))
  488. // }
  489. // ctx.StopExecution()
  490. // }