internal.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2011 Google Inc. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. // Package internal provides support for package appengine.
  5. //
  6. // Programs should not use this package directly. Its API is not stable.
  7. // Use packages appengine and appengine/* instead.
  8. package internal
  9. import (
  10. "fmt"
  11. "github.com/golang/protobuf/proto"
  12. remotepb "google.golang.org/appengine/internal/remote_api"
  13. )
  14. // errorCodeMaps is a map of service name to the error code map for the service.
  15. var errorCodeMaps = make(map[string]map[int32]string)
  16. // RegisterErrorCodeMap is called from API implementations to register their
  17. // error code map. This should only be called from init functions.
  18. func RegisterErrorCodeMap(service string, m map[int32]string) {
  19. errorCodeMaps[service] = m
  20. }
  21. type timeoutCodeKey struct {
  22. service string
  23. code int32
  24. }
  25. // timeoutCodes is the set of service+code pairs that represent timeouts.
  26. var timeoutCodes = make(map[timeoutCodeKey]bool)
  27. func RegisterTimeoutErrorCode(service string, code int32) {
  28. timeoutCodes[timeoutCodeKey{service, code}] = true
  29. }
  30. // APIError is the type returned by appengine.Context's Call method
  31. // when an API call fails in an API-specific way. This may be, for instance,
  32. // a taskqueue API call failing with TaskQueueServiceError::UNKNOWN_QUEUE.
  33. type APIError struct {
  34. Service string
  35. Detail string
  36. Code int32 // API-specific error code
  37. }
  38. func (e *APIError) Error() string {
  39. if e.Code == 0 {
  40. if e.Detail == "" {
  41. return "APIError <empty>"
  42. }
  43. return e.Detail
  44. }
  45. s := fmt.Sprintf("API error %d", e.Code)
  46. if m, ok := errorCodeMaps[e.Service]; ok {
  47. s += " (" + e.Service + ": " + m[e.Code] + ")"
  48. } else {
  49. // Shouldn't happen, but provide a bit more detail if it does.
  50. s = e.Service + " " + s
  51. }
  52. if e.Detail != "" {
  53. s += ": " + e.Detail
  54. }
  55. return s
  56. }
  57. func (e *APIError) IsTimeout() bool {
  58. return timeoutCodes[timeoutCodeKey{e.Service, e.Code}]
  59. }
  60. // CallError is the type returned by appengine.Context's Call method when an
  61. // API call fails in a generic way, such as RpcError::CAPABILITY_DISABLED.
  62. type CallError struct {
  63. Detail string
  64. Code int32
  65. // TODO: Remove this if we get a distinguishable error code.
  66. Timeout bool
  67. }
  68. func (e *CallError) Error() string {
  69. var msg string
  70. switch remotepb.RpcError_ErrorCode(e.Code) {
  71. case remotepb.RpcError_UNKNOWN:
  72. return e.Detail
  73. case remotepb.RpcError_OVER_QUOTA:
  74. msg = "Over quota"
  75. case remotepb.RpcError_CAPABILITY_DISABLED:
  76. msg = "Capability disabled"
  77. case remotepb.RpcError_CANCELLED:
  78. msg = "Canceled"
  79. default:
  80. msg = fmt.Sprintf("Call error %d", e.Code)
  81. }
  82. s := msg + ": " + e.Detail
  83. if e.Timeout {
  84. s += " (timeout)"
  85. }
  86. return s
  87. }
  88. func (e *CallError) IsTimeout() bool {
  89. return e.Timeout
  90. }
  91. // NamespaceMods is a map from API service to a function that will mutate an RPC request to attach a namespace.
  92. // The function should be prepared to be called on the same message more than once; it should only modify the
  93. // RPC request the first time.
  94. var NamespaceMods = make(map[string]func(m proto.Message, namespace string))