Skip to content

Commit

Permalink
add v25 protos for interacting with namespaces
Browse files Browse the repository at this point in the history
  • Loading branch information
mangalaman93 committed Feb 10, 2025
1 parent e2b41cb commit 0fd0571
Show file tree
Hide file tree
Showing 11 changed files with 1,348 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ runtimes:

# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
lint:
ignore:
- linters: [ALL]
paths:
- protos/api/*.pb.go
- protos/api.v25/*.pb.go
enabled:
- [email protected]
- [email protected]
Expand Down
14 changes: 9 additions & 5 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"google.golang.org/protobuf/proto"

"github.com/dgraph-io/dgo/v240/protos/api"
apiv25 "github.com/dgraph-io/dgo/v240/protos/api.v25"
)

const (
Expand All @@ -34,7 +35,9 @@ type Dgraph struct {
jwtMutex sync.RWMutex
jwt api.Jwt
dc []api.DgraphClient
dcv25 []apiv25.DgraphClient
}

type authCreds struct {
token string
}
Expand All @@ -55,18 +58,18 @@ func (a *authCreds) RequireTransportSecurity() bool {
//
// A single Dgraph (client) is thread safe for sharing with multiple goroutines.
func NewDgraphClient(clients ...api.DgraphClient) *Dgraph {
dg := &Dgraph{
dc: clients,
dcv25 := make([]apiv25.DgraphClient, len(clients))
for i, client := range clients {
dcv25[i] = apiv25.NewDgraphClient(api.GetConn(client))
}

return dg
return &Dgraph{dc: clients, dcv25: dcv25}
}

// DialCloud creates a new TLS connection to a Dgraph Cloud backend
//
// It requires the backend endpoint as well as the api token
// Usage:
// conn, err := grpc.DialCloud("CLOUD_ENDPOINT","API_TOKEN")
// conn, err := dgo.DialCloud("CLOUD_ENDPOINT","API_TOKEN")
// if err != nil {
// log.Fatal(err)
// }
Expand Down Expand Up @@ -111,6 +114,7 @@ func DialCloud(endpoint, key string) (*grpc.ClientConn, error) {

func (d *Dgraph) login(ctx context.Context, userid string, password string,
namespace uint64) error {

d.jwtMutex.Lock()
defer d.jwtMutex.Unlock()

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/dgraph-io/dgo/v240

go 1.22.11
go 1.22.12

toolchain go1.23.6

Expand Down
148 changes: 148 additions & 0 deletions ns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* SPDX-FileCopyrightText: © Hypermode Inc. <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

package dgo

import (
"context"
"crypto/x509"
"fmt"
"math/rand"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"

"github.com/dgraph-io/dgo/v240/protos/api"
apiv25 "github.com/dgraph-io/dgo/v240/protos/api.v25"
)

type hmAuthCreds struct {
apiKey string
}

func (a *hmAuthCreds) GetRequestMetadata(ctx context.Context, uri ...string) (
map[string]string, error) {

return map[string]string{"Authorization": fmt.Sprintf("Bearer %s", a.apiKey)}, nil
}

func (a *hmAuthCreds) RequireTransportSecurity() bool {
return true
}

type clientOptions struct {
gopts []grpc.DialOption
}

// ClientOption is a function that modifies the client options.
type ClientOption func(*clientOptions) error

// WithSystemCertPool will use the system cert pool and setup a TLS connection with Dgraph cluster.
func WithSystemCertPool() ClientOption {
return func(o *clientOptions) error {
pool, err := x509.SystemCertPool()
if err != nil {
return fmt.Errorf("failed to create system cert pool: %w", err)
}

creds := credentials.NewClientTLSFromCert(pool, "")
o.gopts = append(o.gopts, grpc.WithTransportCredentials(creds))
return nil
}
}

// WithDgraphAPIKey will use the provided API key for authentication for Dgraph Cloud.
func WithDgraphAPIKey(apiKey string) ClientOption {
return func(o *clientOptions) error {
o.gopts = append(o.gopts, grpc.WithPerRPCCredentials(&authCreds{token: apiKey}))
return nil
}
}

// WithHypermodeAPIKey will use the provided API key for authentication for Hypermode.
func WithHypermodeAPIKey(apiKey string) ClientOption {
return func(o *clientOptions) error {
o.gopts = append(o.gopts, grpc.WithPerRPCCredentials(&hmAuthCreds{apiKey: apiKey}))
return nil
}
}

// WithGrpcOption will add a grpc.DialOption to the client.
// This is useful for setting custom grpc options.
func WithGrpcOption(opt grpc.DialOption) ClientOption {
return func(o *clientOptions) error {
o.gopts = append(o.gopts, opt)
return nil
}
}

// NewClient creates a new Dgraph client for a single endpoint.
func NewClient(endpoint string, opts ...ClientOption) (*Dgraph, error) {
return NewRoundRobinClient([]string{endpoint}, opts...)
}

// NewRoundRobinClient creates a new Dgraph client for a list
// of endpoints. It will round robin among the provided endpoints.
func NewRoundRobinClient(endpoints []string, opts ...ClientOption) (*Dgraph, error) {
co := &clientOptions{}
for _, opt := range opts {
if err := opt(co); err != nil {
return nil, err
}
}

dc := make([]api.DgraphClient, len(endpoints))
dcv25 := make([]apiv25.DgraphClient, len(endpoints))
for i, endpoint := range endpoints {
conn, err := grpc.NewClient(endpoint, co.gopts...)
if err != nil {
return nil, fmt.Errorf("failed to connect to endpoint [%s]: %w", endpoint, err)
}
dc[i] = api.NewDgraphClient(conn)
dcv25[i] = apiv25.NewDgraphClient(conn)
}

return &Dgraph{dc: dc, dcv25: dcv25}, nil
}

func (d *Dgraph) anyClientv25() apiv25.DgraphClient {
//nolint:gosec
return d.dcv25[rand.Intn(len(d.dcv25))]
}

func (d *Dgraph) CreateNamespace(ctx context.Context, name string, password string) error {
dc := d.anyClientv25()
req := &apiv25.CreateNamespaceRequest{NsName: name, Password: password}
_, err := dc.CreateNamespace(ctx, req)
return err
}

func (d *Dgraph) DropNamespace(ctx context.Context, name string) error {
dc := d.anyClientv25()
_, err := dc.DropNamespace(ctx, &apiv25.DropNamespaceRequest{NsName: name})
return err
}

func (d *Dgraph) DropNamespaceWithID(ctx context.Context, nsID uint64) error {
dc := d.anyClientv25()
_, err := dc.DropNamespace(ctx, &apiv25.DropNamespaceRequest{NsId: nsID})
return err
}

func (d *Dgraph) RenameNamespace(ctx context.Context, from string, to string) error {
dc := d.anyClientv25()
req := &apiv25.RenameNamespaceRequest{FromNs: from, ToNs: to}
_, err := dc.RenameNamespace(ctx, req)
return err
}

func (d *Dgraph) ListNamespaces(ctx context.Context) (map[string]*apiv25.Namespace, error) {
dc := d.anyClientv25()
resp, err := dc.ListNamespaces(ctx, &apiv25.ListNamespacesRequest{})
if err != nil {
return nil, err
}
return resp.NsList, nil
}
7 changes: 6 additions & 1 deletion protos/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
# SPDX-License-Identifier: Apache-2.0
#

patchContent := "package api\n\nimport (\n\tgrpc \"google.golang.org/grpc\"\n)\n\nfunc GetConn(c DgraphClient) grpc.ClientConnInterface {\n\treturn c.(*dgraphClient).cc\n}"

.PHONY: clean
clean:
@mkdir -p api && rm -f api/api.pb.go
@rm -rf api && mkdir -p api
@rm -rf api.v25 && mkdir -p api.v25

.PHONY: check
check:
Expand All @@ -16,4 +19,6 @@ check:
.PHONY: regenerate
regenerate: check clean
@protoc --go_out=api --go-grpc_out=api --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative api.proto
@protoc --go_out=api.v25 --go-grpc_out=api.v25 --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative api.v25.proto
@echo $(patchContent) > api/cc.go
@echo Done.
68 changes: 68 additions & 0 deletions protos/api.v25.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: © Hypermode Inc. <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

// Style guide for Protocol Buffer 3.
// Use CamelCase (with an initial capital) for message names – for example,
// SongServerRequest. Use underscore_separated_names for field names – for
// example, song_name.

syntax = "proto3";

package api.v25;

option go_package = "github.com/dgraph-io/dgo/v240/protos/api.v25";

option java_package = "io.dgraph.v25";
option java_outer_classname = "DgraphProto";

service Dgraph {
rpc Ping(PingRequest) returns (PingResponse) {}

// Following operation require guardian of galaxy level access.
rpc CreateNamespace(CreateNamespaceRequest) returns (CreateNamespaceResponse) {}
rpc DropNamespace(DropNamespaceRequest) returns (DropNamespaceResponse) {}
rpc RenameNamespace(RenameNamespaceRequest) returns (RenameNamespaceResponse) {}
rpc ListNamespaces(ListNamespacesRequest) returns (ListNamespacesResponse) {}
}

message PingRequest {}

message PingResponse {
string version = 1;
}

message CreateNamespaceRequest {
string ns_name = 1;
string password = 2;
}

message CreateNamespaceResponse {
uint64 ns_id = 1;
}

message DropNamespaceRequest {
string ns_name = 1;
uint64 ns_id = 2;
}

message DropNamespaceResponse {}

message RenameNamespaceRequest {
string from_ns = 1;
string to_ns = 2;
}

message RenameNamespaceResponse {}

message ListNamespacesRequest {}

message ListNamespacesResponse {
map<string, Namespace> ns_list = 1;
}

message Namespace {
string name = 1;
uint64 id = 2;
}
Loading

0 comments on commit 0fd0571

Please sign in to comment.