api_common.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2015 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
  5. import (
  6. "context"
  7. "errors"
  8. "os"
  9. "github.com/golang/protobuf/proto"
  10. )
  11. type ctxKey string
  12. func (c ctxKey) String() string {
  13. return "appengine context key: " + string(c)
  14. }
  15. var errNotAppEngineContext = errors.New("not an App Engine context")
  16. type CallOverrideFunc func(ctx context.Context, service, method string, in, out proto.Message) error
  17. var callOverrideKey = "holds []CallOverrideFunc"
  18. func WithCallOverride(ctx context.Context, f CallOverrideFunc) context.Context {
  19. // We avoid appending to any existing call override
  20. // so we don't risk overwriting a popped stack below.
  21. var cofs []CallOverrideFunc
  22. if uf, ok := ctx.Value(&callOverrideKey).([]CallOverrideFunc); ok {
  23. cofs = append(cofs, uf...)
  24. }
  25. cofs = append(cofs, f)
  26. return context.WithValue(ctx, &callOverrideKey, cofs)
  27. }
  28. func callOverrideFromContext(ctx context.Context) (CallOverrideFunc, context.Context, bool) {
  29. cofs, _ := ctx.Value(&callOverrideKey).([]CallOverrideFunc)
  30. if len(cofs) == 0 {
  31. return nil, nil, false
  32. }
  33. // We found a list of overrides; grab the last, and reconstitute a
  34. // context that will hide it.
  35. f := cofs[len(cofs)-1]
  36. ctx = context.WithValue(ctx, &callOverrideKey, cofs[:len(cofs)-1])
  37. return f, ctx, true
  38. }
  39. type logOverrideFunc func(level int64, format string, args ...interface{})
  40. var logOverrideKey = "holds a logOverrideFunc"
  41. func WithLogOverride(ctx context.Context, f logOverrideFunc) context.Context {
  42. return context.WithValue(ctx, &logOverrideKey, f)
  43. }
  44. var appIDOverrideKey = "holds a string, being the full app ID"
  45. func WithAppIDOverride(ctx context.Context, appID string) context.Context {
  46. return context.WithValue(ctx, &appIDOverrideKey, appID)
  47. }
  48. var apiHostOverrideKey = ctxKey("holds a string, being the alternate API_HOST")
  49. func withAPIHostOverride(ctx context.Context, apiHost string) context.Context {
  50. return context.WithValue(ctx, apiHostOverrideKey, apiHost)
  51. }
  52. var apiPortOverrideKey = ctxKey("holds a string, being the alternate API_PORT")
  53. func withAPIPortOverride(ctx context.Context, apiPort string) context.Context {
  54. return context.WithValue(ctx, apiPortOverrideKey, apiPort)
  55. }
  56. var namespaceKey = "holds the namespace string"
  57. func withNamespace(ctx context.Context, ns string) context.Context {
  58. return context.WithValue(ctx, &namespaceKey, ns)
  59. }
  60. func NamespaceFromContext(ctx context.Context) string {
  61. // If there's no namespace, return the empty string.
  62. ns, _ := ctx.Value(&namespaceKey).(string)
  63. return ns
  64. }
  65. // FullyQualifiedAppID returns the fully-qualified application ID.
  66. // This may contain a partition prefix (e.g. "s~" for High Replication apps),
  67. // or a domain prefix (e.g. "example.com:").
  68. func FullyQualifiedAppID(ctx context.Context) string {
  69. if id, ok := ctx.Value(&appIDOverrideKey).(string); ok {
  70. return id
  71. }
  72. return fullyQualifiedAppID(ctx)
  73. }
  74. func Logf(ctx context.Context, level int64, format string, args ...interface{}) {
  75. if f, ok := ctx.Value(&logOverrideKey).(logOverrideFunc); ok {
  76. f(level, format, args...)
  77. return
  78. }
  79. c := fromContext(ctx)
  80. if c == nil {
  81. panic(errNotAppEngineContext)
  82. }
  83. logf(c, level, format, args...)
  84. }
  85. // NamespacedContext wraps a Context to support namespaces.
  86. func NamespacedContext(ctx context.Context, namespace string) context.Context {
  87. return withNamespace(ctx, namespace)
  88. }
  89. // SetTestEnv sets the env variables for testing background ticket in Flex.
  90. func SetTestEnv() func() {
  91. var environ = []struct {
  92. key, value string
  93. }{
  94. {"GAE_LONG_APP_ID", "my-app-id"},
  95. {"GAE_MINOR_VERSION", "067924799508853122"},
  96. {"GAE_MODULE_INSTANCE", "0"},
  97. {"GAE_MODULE_NAME", "default"},
  98. {"GAE_MODULE_VERSION", "20150612t184001"},
  99. }
  100. for _, v := range environ {
  101. old := os.Getenv(v.key)
  102. os.Setenv(v.key, v.value)
  103. v.value = old
  104. }
  105. return func() { // Restore old environment after the test completes.
  106. for _, v := range environ {
  107. if v.value == "" {
  108. os.Unsetenv(v.key)
  109. continue
  110. }
  111. os.Setenv(v.key, v.value)
  112. }
  113. }
  114. }