Skip to content

Commit d50f062

Browse files
authored
cli/object: Support SearchV2 (#3122)
2 parents 8554b6d + 93f6531 commit d50f062

File tree

6 files changed

+171
-15
lines changed

6 files changed

+171
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Changelog for NeoFS Node
1212
- Container system attributes verification on IR side (#3107)
1313
- IR `fschain.consensus.rpc.max_websocket_clients` and `fschain.consensus.rpc.session_pool_size` config options (#3126)
1414
- `ObjectService.SearchV2` SN API (#3111)
15+
- `neofs-cli object searchv2` command (#3119)
1516

1617
### Fixed
1718
- `neofs-cli object delete` command output (#3056)

cmd/neofs-cli/modules/object/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func init() {
2424
objectDelCmd,
2525
objectGetCmd,
2626
objectSearchCmd,
27+
searchV2Cmd,
2728
objectHeadCmd,
2829
objectHashCmd,
2930
objectRangeCmd,

cmd/neofs-cli/modules/object/search.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,24 @@ import (
77
"strings"
88

99
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
10+
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
1011
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
1112
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
13+
"github.com/nspcc-dev/neofs-sdk-go/client"
1214
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
15+
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
1316
"github.com/nspcc-dev/neofs-sdk-go/object"
1417
oidSDK "github.com/nspcc-dev/neofs-sdk-go/object/id"
18+
"github.com/nspcc-dev/neofs-sdk-go/session"
1519
"github.com/spf13/cobra"
20+
"github.com/spf13/viper"
21+
)
22+
23+
// searchV2Cmd flags.
24+
var (
25+
searchAttributesFlag = flag[[]string]{f: "attributes"}
26+
searchCountFlag = flag[uint16]{f: "count"}
27+
searchCursorFlag = flag[string]{f: "cursor"}
1628
)
1729

1830
var (
@@ -25,23 +37,44 @@ var (
2537
Args: cobra.NoArgs,
2638
RunE: searchObject,
2739
}
40+
searchV2Cmd = &cobra.Command{
41+
Use: objectSearchCmd.Use + "v2",
42+
Short: objectSearchCmd.Short + " (new)", // TODO: drop suffix on old search deprecation
43+
Long: objectSearchCmd.Long + " (new)", // TODO: desc in details
44+
Args: objectSearchCmd.Args,
45+
RunE: searchV2,
46+
}
2847
)
2948

3049
func initObjectSearchCmd() {
3150
commonflags.Init(objectSearchCmd)
51+
commonflags.Init(searchV2Cmd)
3252
initFlagSession(objectSearchCmd, "SEARCH")
53+
initFlagSession(searchV2Cmd, "SEARCH")
3354

3455
flags := objectSearchCmd.Flags()
56+
flags2 := searchV2Cmd.Flags()
3557

3658
flags.String(commonflags.CIDFlag, "", commonflags.CIDFlagUsage)
3759
_ = objectSearchCmd.MarkFlagRequired(commonflags.CIDFlag)
60+
flags2.String(commonflags.CIDFlag, "", commonflags.CIDFlagUsage)
61+
_ = searchV2Cmd.MarkFlagRequired(commonflags.CIDFlag)
3862

3963
flags.StringSliceVarP(&searchFilters, "filters", "f", nil,
4064
"Repeated filter expressions or files with protobuf JSON")
65+
flags2.StringSliceVarP(&searchFilters, "filters", "f", nil,
66+
"Repeated filter expressions or files with protobuf JSON")
4167

4268
flags.Bool("root", false, "Search for user objects")
69+
flags2.Bool("root", false, "Search for user objects")
4370
flags.Bool("phy", false, "Search physically stored objects")
71+
flags2.Bool("phy", false, "Search physically stored objects")
4472
flags.String(commonflags.OIDFlag, "", "Search object by identifier")
73+
flags2.String(commonflags.OIDFlag, "", "Search object by identifier")
74+
75+
flags2.StringSliceVar(&searchAttributesFlag.v, searchAttributesFlag.f, nil, "Additional attributes to display for suitable objects")
76+
flags2.Uint16Var(&searchCountFlag.v, searchCountFlag.f, 0, "Max number of resulting items. Must not exceed 1000")
77+
flags2.StringVar(&searchCursorFlag.v, searchCursorFlag.f, "", "Cursor to continue previous search")
4578
}
4679

4780
func searchObject(cmd *cobra.Command, _ []string) error {
@@ -175,3 +208,66 @@ func parseSearchFilters(cmd *cobra.Command) (object.SearchFilters, error) {
175208

176209
return fs, nil
177210
}
211+
212+
func searchV2(cmd *cobra.Command, _ []string) error {
213+
var cnr cid.ID
214+
if err := readCID(cmd, &cnr); err != nil {
215+
return err
216+
}
217+
fs, err := parseSearchFilters(cmd)
218+
if err != nil {
219+
return err
220+
}
221+
pk, err := key.GetOrGenerate(cmd)
222+
if err != nil {
223+
return err
224+
}
225+
bt, err := common.ReadBearerToken(cmd, bearerTokenFlag)
226+
if err != nil {
227+
return err
228+
}
229+
st, err := getVerifiedSession(cmd, session.VerbObjectSearch, pk, cnr)
230+
if err != nil {
231+
return err
232+
}
233+
234+
ctx, cancel := commonflags.GetCommandContext(cmd)
235+
defer cancel()
236+
cli, err := internalclient.GetSDKClientByFlag(ctx, commonflags.RPC)
237+
if err != nil {
238+
return err
239+
}
240+
241+
var opts client.SearchObjectsOptions
242+
opts.SetCount(uint32(searchCountFlag.v))
243+
opts.WithXHeaders(parseXHeaders(cmd)...)
244+
if viper.GetUint32(commonflags.TTL) == 1 {
245+
opts.DisableForwarding()
246+
}
247+
if bt != nil {
248+
opts.WithBearerToken(*bt)
249+
}
250+
if st != nil {
251+
opts.WithSessionToken(*st)
252+
}
253+
res, cursor, err := cli.SearchObjects(ctx, cnr, fs, searchAttributesFlag.v, searchCursorFlag.v, neofsecdsa.Signer(*pk), opts)
254+
if err != nil {
255+
return fmt.Errorf("rpc error: %w", err)
256+
}
257+
258+
cmd.Printf("Found %d objects.\n", len(res))
259+
for i := range res {
260+
cmd.Println(res[i].ID)
261+
for j := range searchAttributesFlag.v {
262+
val := res[i].Attributes[j]
263+
if searchAttributesFlag.v[j] == object.AttributeTimestamp {
264+
val = common.PrettyPrintUnixTime(val)
265+
}
266+
fmt.Printf("\t%s: %s\n", searchAttributesFlag.v[j], val)
267+
}
268+
}
269+
if cursor != "" {
270+
cmd.Printf("Cursor: %s\n", cursor)
271+
}
272+
return nil
273+
}

cmd/neofs-cli/modules/object/util.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ import (
2424
"github.com/spf13/viper"
2525
)
2626

27+
type flag[T any] struct {
28+
f string
29+
v T
30+
}
31+
2732
const (
2833
bearerTokenFlag = "bearer"
2934

@@ -203,27 +208,15 @@ func _readVerifiedSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.Private
203208
cmdVerb = session.VerbObjectRangeHash
204209
}
205210

206-
tok, err := getSession(cmd)
207-
if err != nil {
211+
tok, err := getVerifiedSession(cmd, cmdVerb, key, cnr)
212+
if err != nil || tok == nil {
208213
return err
209214
}
210-
if tok == nil {
211-
return nil
212-
}
213215

214216
common.PrintVerbose(cmd, "Checking session correctness...")
215217

216-
switch false {
217-
case tok.AssertContainer(cnr):
218-
return errors.New("unrelated container in the session")
219-
case obj == nil || tok.AssertObject(*obj):
218+
if obj != nil && !tok.AssertObject(*obj) {
220219
return errors.New("unrelated object in the session")
221-
case tok.AssertVerb(cmdVerb):
222-
return errors.New("wrong verb of the session")
223-
case tok.AssertAuthKey((*neofsecdsa.PublicKey)(&key.PublicKey)):
224-
return errors.New("unrelated key in the session")
225-
case tok.VerifySignature():
226-
return errors.New("invalid signature of the session data")
227220
}
228221

229222
common.PrintVerbose(cmd, "Session is correct.")
@@ -232,6 +225,24 @@ func _readVerifiedSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.Private
232225
return nil
233226
}
234227

228+
func getVerifiedSession(cmd *cobra.Command, cmdVerb session.ObjectVerb, key *ecdsa.PrivateKey, cnr cid.ID) (*session.Object, error) {
229+
tok, err := getSession(cmd)
230+
if err != nil || tok == nil {
231+
return tok, err
232+
}
233+
switch false {
234+
case tok.AssertContainer(cnr):
235+
return nil, errors.New("unrelated container in the session")
236+
case tok.AssertVerb(cmdVerb):
237+
return nil, errors.New("wrong verb of the session")
238+
case tok.AssertAuthKey((*neofsecdsa.PublicKey)(&key.PublicKey)):
239+
return nil, errors.New("unrelated key in the session")
240+
case tok.VerifySignature():
241+
return nil, errors.New("invalid signature of the session data")
242+
}
243+
return tok, nil
244+
}
245+
235246
// ReadOrOpenSession opens client connection and calls ReadOrOpenSessionViaClient with it.
236247
func ReadOrOpenSession(ctx context.Context, cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, objs ...oid.ID) error {
237248
cli, err := internal.GetSDKClientByFlag(ctx, commonflags.RPC)

docs/cli-commands/neofs-cli_object.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ Operations with Objects
3131
* [neofs-cli object put](neofs-cli_object_put.md) - Put object to NeoFS
3232
* [neofs-cli object range](neofs-cli_object_range.md) - Get payload range data of an object
3333
* [neofs-cli object search](neofs-cli_object_search.md) - Search object
34+
* [neofs-cli object searchv2](neofs-cli_object_searchv2.md) - Search object (new)
3435

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
## neofs-cli object searchv2
2+
3+
Search object (new)
4+
5+
### Synopsis
6+
7+
Search object (new)
8+
9+
```
10+
neofs-cli object searchv2 [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
--address string Address of wallet account
17+
--attributes strings Additional attributes to display for suitable objects
18+
--bearer string File with signed JSON or binary encoded bearer token
19+
--cid string Container ID.
20+
--count uint16 Max number of resulting items. Must not exceed 1000
21+
--cursor string Cursor to continue previous search
22+
-f, --filters strings Repeated filter expressions or files with protobuf JSON
23+
-g, --generate-key Generate new private key
24+
-h, --help help for searchv2
25+
--oid string Search object by identifier
26+
--phy Search physically stored objects
27+
--root Search for user objects
28+
-r, --rpc-endpoint string Remote node address (as 'multiaddr' or '<host>:<port>')
29+
--session string Filepath to a JSON- or binary-encoded token of the object SEARCH session
30+
-t, --timeout duration Timeout for the operation (default 15s)
31+
--ttl uint32 TTL value in request meta header (default 2)
32+
-w, --wallet string Path to the wallet
33+
-x, --xhdr strings Request X-Headers in form of Key=Value
34+
```
35+
36+
### Options inherited from parent commands
37+
38+
```
39+
-c, --config string Config file (default is $HOME/.config/neofs-cli/config.yaml)
40+
-v, --verbose Verbose output
41+
```
42+
43+
### SEE ALSO
44+
45+
* [neofs-cli object](neofs-cli_object.md) - Operations with Objects
46+

0 commit comments

Comments
 (0)