如何从 appengine.Context 创建云 context.Context

How can I create cloud context.Context from appengine.Context

如果我有 appengine.Context 而不是 context.Context,我不知道如何调用 cloud.WithContextgoogle.DefaultClient

有(旧)"appengine" 和(新)"google.golang.org/appengine" 包。第一个带来自定义 appengine.Context 而第二个带来来自 "golang.org/x/net/context"

context.Context

整个google.golang.org/cloud预计只有context.Context

我很乐意转而使用新的 "google.golang.org/appengine",但我一直坚持使用尚未移植的 runtime.RunInBackground。来自 https://github.com/golang/appengine:

appengine/aetest, appengine/cloudsql and appengine/runtime have not been ported yet.

如果 appengine/runtime 已经被移植,我可以写什么:

import (
    "golang.org/x/net/context"

    "google.golang.org/appengine"
    "google.golang.org/appengine/runtime"
    "google.golang.org/cloud"
    "google.golang.org/cloud/storage"
)

func handler(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    runtime.RunInBackground(c, func(ctx context.Context) {
        hc, _ := google.DefaultClient(ctx, storage.ScopeFullControl)
        cc := cloud.WithContext(ctx, appengine.AppID(ctx), hc)
        …
   })
}

但是还没有"google.golang.org/appengine/runtime"。所以我有

runtime.RunInBackground(c, func(ctx appengine.Context) {

这样做:

func getCloudContext(appengineContext context.Context) context.Context {
    hc := &http.Client{
        Transport: &oauth2.Transport{
            Source: google.AppEngineTokenSource(appengineContext, storage.ScopeFullControl),
            Base:   &urlfetch.Transport{Context: appengineContext},
        },
    }

    return cloud.NewContext(appengine.AppID(appengineContext), hc)
}

或者,如果通过开发服务器传递凭据不起作用,您也可以使用显式凭据:

func getCloudContext(aeCtx context.Context) (context.Context, error) {
    data, err := ioutil.ReadFile("/path/to/credentials.json")
    if err != nil {
        return nil, err
    }

    conf, err := google.JWTConfigFromJSON(
        data,
        storage.ScopeFullControl,
    )
    if err != nil {
        return nil, err
    }

    tokenSource := conf.TokenSource(aeCtx)

    hc := &http.Client{
        Transport: &oauth2.Transport{
            Source: tokenSource,
            Base:   &urlfetch.Transport{Context: aeCtx},
        },
    }

    return cloud.NewContext(appengine.AppID(aeCtx), hc), nil
}

这里是你可以做你想做的事情的方法:

import (
    "code.google.com/p/goauth2/appengine/serviceaccount"
    "golang.org/x/net/context"
    "appengine"
)

// oauth2 module requires a context.Context so use goauth2 for now
func CloudContext(c appengine.Context, scopes ...string) context.Context {
    client, _ := serviceaccount.NewClient(c, scopes...)
    return cloud.WithContext(context.Background(), appengine.AppID(c), client)
}

您可以从 https://code.google.com/p/goauth2/source/browse/

获取 goauth2 库

目前无法从(旧)appengine.Context 获取云 context.Context

托管 VM 的解决方案

一个月前 BackgroundContext() 方法 was addedgoogle.golang.org/appengine(仅适用于托管 VM)。这允许启动 goroutine 并获取云 context.Context 而无需将其传递给.

经典 Appengine 的解决方案

暂时没有解决方案。