diff --git a/datastore/datastore.go b/datastore/datastore.go index bdc09b830bea..b930371362c7 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -75,6 +75,12 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio option.WithoutAuthentication(), option.WithGRPCDialOption(grpc.WithInsecure()), } + if projectID == DetectProjectID { + projectID, _ = detectProjectID(ctx, opts...) + if projectID == "" { + projectID = "dummy-emulator-datastore-project" + } + } } else { o = []option.ClientOption{ option.WithEndpoint(prodAddr), @@ -96,16 +102,11 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio o = append(o, opts...) if projectID == DetectProjectID { - creds, err := transport.Creds(ctx, o...) + detected, err := detectProjectID(ctx, opts...) if err != nil { - return nil, fmt.Errorf("fetching creds: %v", err) + return nil, err } - - if creds.ProjectID == "" { - return nil, errors.New("datastore: see the docs on DetectProjectID") - } - - projectID = creds.ProjectID + projectID = detected } if projectID == "" { @@ -122,6 +123,17 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio }, nil } +func detectProjectID(ctx context.Context, opts ...option.ClientOption) (string, error) { + creds, err := transport.Creds(ctx, opts...) + if err != nil { + return "", fmt.Errorf("fetching creds: %v", err) + } + if creds.ProjectID == "" { + return "", errors.New("datastore: see the docs on DetectProjectID") + } + return creds.ProjectID, nil +} + var ( // ErrInvalidEntityType is returned when functions like Get or Next are // passed a dst or src argument of invalid type. diff --git a/firestore/client.go b/firestore/client.go index 1e6ac8c46b17..4a7f3a1158d8 100644 --- a/firestore/client.go +++ b/firestore/client.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "io" + "log" "os" "strings" "time" @@ -63,23 +64,28 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio var o []option.ClientOption // If this environment variable is defined, configure the client to talk to the emulator. if addr := os.Getenv("FIRESTORE_EMULATOR_HOST"); addr != "" { + log.Printf("Dial: %v", addr) conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithPerRPCCredentials(emulatorCreds{})) if err != nil { return nil, fmt.Errorf("firestore: dialing address from env var FIRESTORE_EMULATOR_HOST: %s", err) } + log.Printf("Emulator conn: %v", conn) o = []option.ClientOption{option.WithGRPCConn(conn)} + if projectID == DetectProjectID { + projectID, _ = detectProjectID(ctx, opts...) + if projectID == "" { + projectID = "dummy-emulator-firestore-project" + } + } } o = append(o, opts...) if projectID == DetectProjectID { - creds, err := transport.Creds(ctx, o...) + detected, err := detectProjectID(ctx, o...) if err != nil { - return nil, fmt.Errorf("fetching creds: %v", err) - } - if creds.ProjectID == "" { - return nil, errors.New("firestore: see the docs on DetectProjectID") + return nil, err } - projectID = creds.ProjectID + projectID = detected } vc, err := vkit.NewClient(ctx, o...) @@ -93,7 +99,17 @@ func NewClient(ctx context.Context, projectID string, opts ...option.ClientOptio databaseID: "(default)", // always "(default)", for now } return c, nil +} +func detectProjectID(ctx context.Context, opts ...option.ClientOption) (string, error) { + creds, err := transport.Creds(ctx, opts...) + if err != nil { + return "", fmt.Errorf("fetching creds: %v", err) + } + if creds.ProjectID == "" { + return "", errors.New("firestore: see the docs on DetectProjectID") + } + return creds.ProjectID, nil } // Close closes any resources held by the client.