package frostfs import ( "context" "errors" "fmt" "io" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tokens" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree" apitree "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/tree" treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree" ) type GetNodeByPathResponseInfoWrapper struct { response *apitree.GetNodeByPathResponseInfo } func (n GetNodeByPathResponseInfoWrapper) GetNodeID() []uint64 { return []uint64{n.response.GetNodeID()} } func (n GetNodeByPathResponseInfoWrapper) GetParentID() []uint64 { return []uint64{n.response.GetParentID()} } func (n GetNodeByPathResponseInfoWrapper) GetTimestamp() []uint64 { return []uint64{n.response.GetTimestamp()} } func (n GetNodeByPathResponseInfoWrapper) GetMeta() []tree.Meta { res := make([]tree.Meta, len(n.response.GetMeta())) for i, value := range n.response.GetMeta() { res[i] = value } return res } type PoolWrapper struct { p *treepool.Pool } func NewPoolWrapper(p *treepool.Pool) *PoolWrapper { return &PoolWrapper{p: p} } func (w *PoolWrapper) GetNodes(ctx context.Context, prm *tree.GetNodesParams) ([]tree.NodeResponse, error) { poolPrm := treepool.GetNodesParams{ CID: prm.CnrID, TreeID: prm.TreeID, Path: prm.Path, Meta: prm.Meta, PathAttribute: tree.FileNameKey, LatestOnly: prm.LatestOnly, AllAttrs: prm.AllAttrs, BearerToken: getBearer(ctx), } nodes, err := w.p.GetNodes(ctx, poolPrm) if err != nil { return nil, handleError(err) } res := make([]tree.NodeResponse, len(nodes)) for i, info := range nodes { 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(err error) error { if err == nil { return nil } if errors.Is(err, treepool.ErrNodeNotFound) { return fmt.Errorf("%w: %s", tree.ErrNodeNotFound, err.Error()) } if errors.Is(err, treepool.ErrNodeAccessDenied) { return fmt.Errorf("%w: %s", tree.ErrNodeAccessDenied, err.Error()) } return err } func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32, sort bool) ([]tree.NodeResponse, error) { order := treepool.NoneOrder if sort { order = treepool.AscendingOrder } poolPrm := treepool.GetSubTreeParams{ CID: bktInfo.CID, TreeID: treeID, RootID: rootID, Depth: depth, BearerToken: getBearer(ctx), Order: order, } if len(rootID) == 1 && rootID[0] == 0 { // storage node interprets 'nil' value as []uint64{0} // gate wants to send 'nil' value instead of []uint64{0}, because // it provides compatibility with previous tree service api where // single uint64(0) value is dropped from signature poolPrm.RootID = nil } subTreeReader, err := w.p.GetSubTree(ctx, poolPrm) if err != nil { return nil, handleError(err) } var subtree []tree.NodeResponse node, err := subTreeReader.Next() for err == nil { subtree = append(subtree, GetSubTreeResponseBodyWrapper{node}) node, err = subTreeReader.Next() } if err != io.EOF { return nil, handleError(err) } return subtree, nil } type GetSubTreeResponseBodyWrapper struct { response *apitree.GetSubTreeResponseBody } func (n GetSubTreeResponseBodyWrapper) GetNodeID() []uint64 { return n.response.GetNodeID() } func (n GetSubTreeResponseBodyWrapper) GetParentID() []uint64 { resp := n.response.GetParentID() if resp == nil { // storage sends nil that should be interpreted as []uint64{0} // due to protobuf compatibility, see 'GetSubTree' function return []uint64{0} } return resp } func (n GetSubTreeResponseBodyWrapper) GetTimestamp() []uint64 { return n.response.GetTimestamp() } func (n GetSubTreeResponseBodyWrapper) GetMeta() []tree.Meta { res := make([]tree.Meta, len(n.response.GetMeta())) for i, value := range n.response.GetMeta() { res[i] = value } return res }