9aee5efd99
* pointerdb: separate client and server packages the reason for this is so that things the server needs (bolt, auth) don't get imported if all you need is the client. will result in smaller binaries and less flag definitions * review comments
144 lines
3.7 KiB
Go
144 lines
3.7 KiB
Go
// Copyright (C) 2018 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package pdbclient
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
monkit "gopkg.in/spacemonkeygo/monkit.v2"
|
|
|
|
p "storj.io/storj/pkg/paths"
|
|
pb "storj.io/storj/protos/pointerdb"
|
|
"storj.io/storj/storage"
|
|
)
|
|
|
|
var (
|
|
mon = monkit.Package()
|
|
)
|
|
|
|
// PointerDB creates a grpcClient
|
|
type PointerDB struct {
|
|
grpcClient pb.PointerDBClient
|
|
APIKey []byte
|
|
}
|
|
|
|
// a compiler trick to make sure *Overlay implements Client
|
|
var _ Client = (*PointerDB)(nil)
|
|
|
|
// ListItem is a single item in a listing
|
|
type ListItem struct {
|
|
Path p.Path
|
|
Pointer *pb.Pointer
|
|
}
|
|
|
|
// Client services offerred for the interface
|
|
type Client interface {
|
|
Put(ctx context.Context, path p.Path, pointer *pb.Pointer) error
|
|
Get(ctx context.Context, path p.Path) (*pb.Pointer, error)
|
|
List(ctx context.Context, prefix, startAfter, endBefore p.Path,
|
|
recursive bool, limit int, metaFlags uint32) (
|
|
items []ListItem, more bool, err error)
|
|
Delete(ctx context.Context, path p.Path) error
|
|
}
|
|
|
|
// NewClient initializes a new pointerdb client
|
|
func NewClient(address string, APIKey []byte) (*PointerDB, error) {
|
|
c, err := clientConnection(address, grpc.WithInsecure())
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &PointerDB{
|
|
grpcClient: c,
|
|
APIKey: APIKey,
|
|
}, nil
|
|
}
|
|
|
|
// a compiler trick to make sure *PointerDB implements Client
|
|
var _ Client = (*PointerDB)(nil)
|
|
|
|
// ClientConnection makes a server connection
|
|
func clientConnection(serverAddr string, opts ...grpc.DialOption) (pb.PointerDBClient, error) {
|
|
conn, err := grpc.Dial(serverAddr, opts...)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return pb.NewPointerDBClient(conn), nil
|
|
}
|
|
|
|
// Put is the interface to make a PUT request, needs Pointer and APIKey
|
|
func (pdb *PointerDB) Put(ctx context.Context, path p.Path, pointer *pb.Pointer) (err error) {
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
_, err = pdb.grpcClient.Put(ctx, &pb.PutRequest{Path: path.String(), Pointer: pointer, APIKey: pdb.APIKey})
|
|
|
|
return err
|
|
}
|
|
|
|
// Get is the interface to make a GET request, needs PATH and APIKey
|
|
func (pdb *PointerDB) Get(ctx context.Context, path p.Path) (pointer *pb.Pointer, err error) {
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
res, err := pdb.grpcClient.Get(ctx, &pb.GetRequest{Path: path.String(), APIKey: pdb.APIKey})
|
|
if err != nil {
|
|
if status.Code(err) == codes.NotFound {
|
|
return nil, storage.ErrKeyNotFound.Wrap(err)
|
|
}
|
|
return nil, Error.Wrap(err)
|
|
}
|
|
|
|
pointer = &pb.Pointer{}
|
|
err = proto.Unmarshal(res.GetPointer(), pointer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pointer, nil
|
|
}
|
|
|
|
// List is the interface to make a LIST request, needs StartingPathKey, Limit, and APIKey
|
|
func (pdb *PointerDB) List(ctx context.Context, prefix, startAfter, endBefore p.Path,
|
|
recursive bool, limit int, metaFlags uint32) (
|
|
items []ListItem, more bool, err error) {
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
res, err := pdb.grpcClient.List(ctx, &pb.ListRequest{
|
|
Prefix: prefix.String(),
|
|
StartAfter: startAfter.String(),
|
|
EndBefore: endBefore.String(),
|
|
Recursive: recursive,
|
|
Limit: int32(limit),
|
|
MetaFlags: metaFlags,
|
|
APIKey: pdb.APIKey,
|
|
})
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
list := res.GetItems()
|
|
items = make([]ListItem, len(list))
|
|
for i, itm := range list {
|
|
items[i] = ListItem{
|
|
Path: p.New(itm.GetPath()),
|
|
Pointer: itm.GetPointer(),
|
|
}
|
|
}
|
|
|
|
return items, res.GetMore(), nil
|
|
}
|
|
|
|
// Delete is the interface to make a Delete request, needs Path and APIKey
|
|
func (pdb *PointerDB) Delete(ctx context.Context, path p.Path) (err error) {
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
_, err = pdb.grpcClient.Delete(ctx, &pb.DeleteRequest{Path: path.String(), APIKey: pdb.APIKey})
|
|
|
|
return err
|
|
}
|