# #google-app-engine #go
#google-app-engine #Вперед
Вопрос:
Если я установлю пространство имен my context.Context
и вызову функцию задержки:
ctx := appengine.NewContext(r)
ctx, err := appengine.Namespace(ctx, "mynamespace")
delayFunc.Call(ctx)
Как я могу найти его имя:
var delayFunc = delay.Func("my-func", func(ctx context.Context) {
// How do I extract "mynamespace" from ctx?
})
Является ли следующая приемлемая практика?
var delayFunc = delay.Func("my-func", func(ctx context.Context) {
n := datastore.NewKey(ctx, "E", "e", 0, nil).Namespace()
// n == "mynamespace"
})
Это работает, но похоже на взлом.
Ответ №1:
К сожалению, вам не повезло. Appengine не предоставляет (экспортированный) вызов API для доступа к пространству имен, связанному с контекстом.
Связь пространства имен с контекстом обрабатывается appengine/internal
пакетом, но «программы не должны использовать этот пакет напрямую». Контекст с пространством имен получается internal.NamespacedContext()
вызовом, и в нем реализуется «извлечение» пространства имен из контекста internal.NamespaceFromContext()
. Они не являются частью общедоступного API, поэтому вы не можете (не должны) их использовать.
В основном у вас есть 2 варианта. Один из них — это «хакерский» способ, который вы представили, который работает, и вы можете продолжать его использовать.
Другой способ — обработать его вручную, например, вручную поместив пространство имен в контекст с помощью вашего собственного ключа, например:
var namespaceKey = "myNsKey"
ctx = context.WithValue(ctx, namespaceKey, "mynamespace")
И когда вам это нужно, вы можете получить его следующим образом:
ns := ctx.Value(namespaceKey)
Да, это связано с необходимостью обновлять его вручную, и если вы забыли, вы получите «недопустимое» или пустое пространство имен. Так что лично я бы пока пошел по вашему «хакерскому» пути (пока эта функциональность не будет добавлена в общедоступный API, если вообще когда-либо).
Если вы выберете ручной способ, чтобы избавиться от фактора «риска», вы могли бы создать вспомогательную функцию, которая могла бы позаботиться об этом вместе с appengine.Namespace()
вызовом, чтобы вы не забыли об этом, и это было бы безопасно. Это может выглядеть так:
func SetNS(ctx context.Context, ns string) context.Context {
ctx = ctx, err := appengine.Namespace(ctx, ns)
if err != nil {
// handle error
}
ctx = context.WithValue(ctx, namespaceKey, ns)
return ctx
}
И используя его:
ctx = SetNS(ctx, "mynamespace")
Но это может быть редкий случай, когда вам нужно получить доступ к пространству имен из контекста, так как, когда вам это понадобится, может быть достаточно просто передать контекст в соответствующий вызов API (Appengine), который может извлечь его из контекста.