frostfs-http-gw/internal/frostfs/services/tree_client_grpc.go

115 lines
2.9 KiB
Go
Raw Normal View History

package services
import (
"context"
"fmt"
"strings"
grpcService "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/frostfs/services/tree"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/tokens"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"google.golang.org/grpc"
)
type GetNodeByPathResponseInfoWrapper struct {
response *grpcService.GetNodeByPathResponse_Info
}
func (n GetNodeByPathResponseInfoWrapper) GetMeta() []tree.Meta {
res := make([]tree.Meta, len(n.response.Meta))
for i, value := range n.response.Meta {
res[i] = value
}
return res
}
type GetSubTreeResponseBodyWrapper struct {
response *grpcService.GetSubTreeResponse_Body
}
func (n GetSubTreeResponseBodyWrapper) GetMeta() []tree.Meta {
res := make([]tree.Meta, len(n.response.Meta))
for i, value := range n.response.Meta {
res[i] = value
}
return res
}
type ServiceClientGRPC struct {
key *keys.PrivateKey
conn *grpc.ClientConn
service grpcService.TreeServiceClient
}
func NewTreeServiceClientGRPC(ctx context.Context, addr string, key *keys.PrivateKey, grpcOpts ...grpc.DialOption) (*ServiceClientGRPC, error) {
conn, err := grpc.Dial(addr, grpcOpts...)
if err != nil {
return nil, fmt.Errorf("did not connect: %v", err)
}
c := grpcService.NewTreeServiceClient(conn)
if _, err = c.Healthcheck(ctx, &grpcService.HealthcheckRequest{}); err != nil {
return nil, fmt.Errorf("healthcheck: %w", err)
}
return &ServiceClientGRPC{
key: key,
conn: conn,
service: c,
}, nil
}
func (c *ServiceClientGRPC) GetNodes(ctx context.Context, p *tree.GetNodesParams) ([]tree.NodeResponse, error) {
request := &grpcService.GetNodeByPathRequest{
Body: &grpcService.GetNodeByPathRequest_Body{
ContainerId: p.CnrID[:],
TreeId: p.TreeID,
Path: p.Path,
Attributes: p.Meta,
PathAttribute: tree.FileNameKey,
LatestOnly: p.LatestOnly,
AllAttributes: p.AllAttrs,
BearerToken: getBearer(ctx),
},
}
if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &grpcService.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return nil, err
}
resp, err := c.service.GetNodeByPath(ctx, request)
if err != nil {
return nil, handleError("failed to get node by path", err)
}
res := make([]tree.NodeResponse, len(resp.GetBody().GetNodes()))
for i, info := range resp.GetBody().GetNodes() {
res[i] = GetNodeByPathResponseInfoWrapper{info}
}
return res, nil
}
func getBearer(ctx context.Context) []byte {
token, err := tokens.LoadBearerToken(ctx)
if err != nil {
return nil
}
return token.Marshal()
}
func handleError(msg string, err error) error {
if strings.Contains(err.Error(), "not found") {
return fmt.Errorf("%w: %s", tree.ErrNodeNotFound, err.Error())
} else if strings.Contains(err.Error(), "is denied by") {
return fmt.Errorf("%w: %s", tree.ErrNodeAccessDenied, err.Error())
}
return fmt.Errorf("%s: %w", msg, err)
}