Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added function to login with refresh token etc #39

Merged
merged 5 commits into from
Jan 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ package dgo

import (
"context"
"fmt"
"math/rand"
"strings"
"sync"

"github.com/dgraph-io/dgo/protos/api"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)

// Dgraph is a transaction aware client to a set of dgraph server instances.
Expand All @@ -46,6 +51,9 @@ func NewDgraphClient(clients ...api.DgraphClient) *Dgraph {
}

func (d *Dgraph) Login(ctx context.Context, userid string, password string) error {
d.jwtMutex.Lock()
defer d.jwtMutex.Unlock()

dc := d.anyClient()
loginRequest := &api.LoginRequest{
Userid: userid,
Expand All @@ -56,24 +64,42 @@ func (d *Dgraph) Login(ctx context.Context, userid string, password string) erro
return err
}

return d.jwt.Unmarshal(resp.Json)
}

func (d *Dgraph) retryLogin(ctx context.Context) error {
d.jwtMutex.Lock()
defer d.jwtMutex.Unlock()

if len(d.jwt.RefreshJwt) == 0 {
return fmt.Errorf("refresh jwt should not be empty")
}

dc := d.anyClient()
loginRequest := &api.LoginRequest{
RefreshToken: d.jwt.RefreshJwt,
}
resp, err := dc.Login(ctx, loginRequest)
if err != nil {
return err
}
return d.jwt.Unmarshal(resp.Json)
}

func (d *Dgraph) GetContext(ctx context.Context) context.Context {
func (d *Dgraph) getContext(ctx context.Context) context.Context {
d.jwtMutex.RLock()
defer d.jwtMutex.RUnlock()
newCtx := ctx
if len(d.jwt.AccessJwt) > 0 {
newCtx = context.WithValue(newCtx, "accessJwt", d.jwt.AccessJwt)
}
if len(d.jwt.RefreshJwt) > 0 {
newCtx = context.WithValue(newCtx, "refreshJwt", d.jwt.RefreshJwt)
md, ok := metadata.FromOutgoingContext(ctx)
if !ok {
// no metadata key is in the context, add one
md = metadata.New(nil)
}
md.Set("accessJwt", d.jwt.AccessJwt)
return metadata.NewOutgoingContext(ctx, md)
}

// otherwise return the jwt as it is
return newCtx
return ctx
}

// By setting various fields of api.Operation, Alter can be used to do the
Expand All @@ -86,10 +112,33 @@ func (d *Dgraph) GetContext(ctx context.Context) context.Context {
// 3. Drop the database.
func (d *Dgraph) Alter(ctx context.Context, op *api.Operation) error {
dc := d.anyClient()

ctx = d.getContext(ctx)
_, err := dc.Alter(ctx, op)

if isJwtExpired(err) {
err = d.retryLogin(ctx)
if err != nil {
return err
}
ctx = d.getContext(ctx)
_, err = dc.Alter(ctx, op)
}

return err
}

// isJwtExpired returns true if the error indicates that the jwt has expired
func isJwtExpired(err error) bool {
if err == nil {
return false
}

st, ok := status.FromError(err)
return ok && st.Code() == codes.Unauthenticated &&
strings.Contains(err.Error(), "Token is expired")
}

func (d *Dgraph) anyClient() api.DgraphClient {
return d.dc[rand.Intn(len(d.dc))]
}
Expand Down
138 changes: 40 additions & 98 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,38 @@ import (
"google.golang.org/grpc"
)

func ExampleDgraph_Alter_dropAll() {
type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)
return dgo.NewDgraphClient(dc), func() {
if err := conn.Close(); err != nil {
log.Printf("Error while closing connection:%v", err)
}
}
}

func ExampleDgraph_Alter_dropAll() {
dg, cancel := getDgraphClient()
defer cancel()
op := api.Operation{
DropAll: true,
}
ctx := context.Background()
if err := dg.Alter(ctx, &op); err != nil {
log.Fatal(err)
}

fmt.Println(err)

// Output: <nil>
// Output:
}

func ExampleTxn_Query_variables() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
type Person struct {
Uid string `json:"uid,omitempty"`
Name string `json:"name,omitempty"`
Expand All @@ -72,7 +71,7 @@ func ExampleTxn_Query_variables() {
`

ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -146,15 +145,8 @@ func ExampleTxn_Mutate() {
School []School `json:"school,omitempty"`
}

conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
// While setting an object if a struct has a Uid then its properties in the graph are updated
// else a new node is created.
// In the example below new nodes for Alice, Bob and Charlie and school are created (since they
Expand Down Expand Up @@ -187,8 +179,7 @@ func ExampleTxn_Mutate() {
`

ctx := context.Background()
err = dg.Alter(ctx, op)
if err != nil {
if err := dg.Alter(ctx, op); err != nil {
log.Fatal(err)
}

Expand Down Expand Up @@ -251,15 +242,8 @@ func ExampleTxn_Mutate() {
}

func ExampleTxn_Mutate_bytes() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
type Person struct {
Uid string `json:"uid,omitempty"`
Name string `json:"name,omitempty"`
Expand All @@ -272,7 +256,7 @@ func ExampleTxn_Mutate_bytes() {
`

ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -337,23 +321,16 @@ func ExampleTxn_Query_unmarshal() {
School []School `json:"school,omitempty"`
}

conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
op := &api.Operation{}
op.Schema = `
age: int .
married: bool .
`

ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -454,15 +431,8 @@ func ExampleTxn_Query_unmarshal() {
}

func ExampleTxn_Mutate_facets() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
// Doing a dropAll isn't required by the user. We do it here so that we can verify that the
// example runs as expected.
op := api.Operation{
Expand All @@ -478,7 +448,7 @@ func ExampleTxn_Mutate_facets() {
name: string @index(exact) .
`

err = dg.Alter(ctx, &op)
err := dg.Alter(ctx, &op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -577,15 +547,8 @@ func ExampleTxn_Mutate_facets() {
}

func ExampleTxn_Mutate_list() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)
// This example shows example for SetObject for predicates with list type.
dg, cancel := getDgraphClient()
defer cancel() // This example shows example for SetObject for predicates with list type.
type Person struct {
Uid string `json:"uid"`
Address []string `json:"address"`
Expand All @@ -603,7 +566,7 @@ func ExampleTxn_Mutate_list() {
phone_number: [int] .
`
ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -653,15 +616,8 @@ func ExampleTxn_Mutate_list() {
}

func ExampleDeleteEdges() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
op := &api.Operation{}
op.Schema = `
age: int .
Expand All @@ -671,7 +627,7 @@ func ExampleDeleteEdges() {
`

ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -774,15 +730,8 @@ func ExampleDeleteEdges() {
}

func ExampleTxn_Mutate_deleteNode() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
// In this test we check S * * deletion.
type Person struct {
Uid string `json:"uid,omitempty"`
Expand Down Expand Up @@ -812,7 +761,7 @@ func ExampleTxn_Mutate_deleteNode() {
`

ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -913,15 +862,8 @@ func ExampleTxn_Mutate_deleteNode() {
}

func ExampleTxn_Mutate_deletePredicate() {
conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
if err != nil {
log.Fatal("While trying to dial gRPC")
}
defer conn.Close()

dc := api.NewDgraphClient(conn)
dg := dgo.NewDgraphClient(dc)

dg, cancel := getDgraphClient()
defer cancel()
type Person struct {
Uid string `json:"uid,omitempty"`
Name string `json:"name,omitempty"`
Expand Down Expand Up @@ -950,7 +892,7 @@ func ExampleTxn_Mutate_deletePredicate() {
`

ctx := context.Background()
err = dg.Alter(ctx, op)
err := dg.Alter(ctx, op)
if err != nil {
log.Fatal(err)
}
Expand Down
Loading