9
9
"net/url"
10
10
"strconv"
11
11
"strings"
12
+ "time"
12
13
13
14
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
14
15
"github.com/nspcc-dev/neo-go/pkg/util"
@@ -17,6 +18,8 @@ import (
17
18
"github.com/nspcc-dev/neofs-sdk-go/object"
18
19
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
19
20
"github.com/nspcc-dev/neofs-sdk-go/user"
21
+ "google.golang.org/grpc/codes"
22
+ "google.golang.org/grpc/status"
20
23
)
21
24
22
25
const (
@@ -45,41 +48,48 @@ var (
45
48
// URI scheme is "neofs:<Container-ID>/<Object-ID/<Command>/<Params>".
46
49
// If Command is not provided, full object is requested.
47
50
func Get (ctx context.Context , priv * keys.PrivateKey , u * url.URL , addr string ) (io.ReadCloser , error ) {
48
- objectAddr , ps , err := parseNeoFSURL ( u )
51
+ c , err := GetSDKClient ( ctx , addr , 0 )
49
52
if err != nil {
50
- return nil , err
53
+ return clientCloseWrapper { c : c }, fmt . Errorf ( "failed to create client: %w" , err )
51
54
}
55
+ return GetWithClient (ctx , c , priv , u , true )
56
+ }
52
57
53
- c , err := client .New (client.PrmInit {})
58
+ // GetWithClient returns a neofs object from the provided url using the provided client.
59
+ // URI scheme is "neofs:<Container-ID>/<Object-ID/<Command>/<Params>".
60
+ // If Command is not provided, full object is requested. If wrapClientCloser is true,
61
+ // the client will be closed when the returned ReadCloser is closed.
62
+ func GetWithClient (ctx context.Context , c * client.Client , priv * keys.PrivateKey , u * url.URL , wrapClientCloser bool ) (io.ReadCloser , error ) {
63
+ objectAddr , ps , err := parseNeoFSURL (u )
54
64
if err != nil {
55
- return nil , fmt . Errorf ( "failed to create client: %w" , err )
65
+ return nil , err
56
66
}
57
-
58
67
var (
59
- res = clientCloseWrapper { c : c }
60
- prmd client. PrmDial
68
+ res io. ReadCloser
69
+ s = user . NewAutoIDSignerRFC6979 ( priv . PrivateKey )
61
70
)
62
- prmd .SetServerURI (addr )
63
- prmd .SetContext (ctx )
64
- err = c .Dial (prmd ) //nolint:contextcheck // contextcheck: Function `Dial->Balance->SendUnary->Init->setNeoFSAPIServer` should pass the context parameter
65
- if err != nil {
66
- return res , err
67
- }
68
-
69
- var s = user .NewAutoIDSignerRFC6979 (priv .PrivateKey )
70
71
switch {
71
- case len (ps ) == 0 || ps [0 ] == "" : // Get request
72
- res . ReadCloser , err = getPayload (ctx , s , c , objectAddr )
72
+ case len (ps ) == 0 || ps [0 ] == "" :
73
+ res , err = getPayload (ctx , s , c , objectAddr )
73
74
case ps [0 ] == rangeCmd :
74
- res . ReadCloser , err = getRange (ctx , s , c , objectAddr , ps [1 :]... )
75
+ res , err = getRange (ctx , s , c , objectAddr , ps [1 :]... )
75
76
case ps [0 ] == headerCmd :
76
- res . ReadCloser , err = getHeader (ctx , s , c , objectAddr )
77
+ res , err = getHeader (ctx , s , c , objectAddr )
77
78
case ps [0 ] == hashCmd :
78
- res . ReadCloser , err = getHash (ctx , s , c , objectAddr , ps [1 :]... )
79
+ res , err = getHash (ctx , s , c , objectAddr , ps [1 :]... )
79
80
default :
80
- err = ErrInvalidCommand
81
+ return nil , ErrInvalidCommand
82
+ }
83
+ if err != nil {
84
+ return nil , err
85
+ }
86
+ if wrapClientCloser {
87
+ return clientCloseWrapper {
88
+ c : c ,
89
+ ReadCloser : res ,
90
+ }, nil
81
91
}
82
- return res , err
92
+ return res , nil
83
93
}
84
94
85
95
type clientCloseWrapper struct {
@@ -92,7 +102,12 @@ func (w clientCloseWrapper) Close() error {
92
102
if w .ReadCloser != nil {
93
103
res = w .ReadCloser .Close ()
94
104
}
95
- w .c .Close ()
105
+ if w .c != nil {
106
+ closeErr := w .c .Close ()
107
+ if closeErr != nil && res == nil {
108
+ res = closeErr
109
+ }
110
+ }
96
111
return res
97
112
}
98
113
@@ -220,3 +235,58 @@ func parseRange(s string) (*object.Range, error) {
220
235
r .SetLength (length )
221
236
return r , nil
222
237
}
238
+
239
+ // ObjectSearch returns a list of object IDs from the provided container.
240
+ func ObjectSearch (ctx context.Context , c * client.Client , priv * keys.PrivateKey , containerIDStr string , prm client.PrmObjectSearch ) ([]oid.ID , error ) {
241
+ var (
242
+ s = user .NewAutoIDSignerRFC6979 (priv .PrivateKey )
243
+ objectIDs []oid.ID
244
+ containerID cid.ID
245
+ )
246
+ err := containerID .DecodeString (containerIDStr )
247
+ if err != nil {
248
+ return nil , fmt .Errorf ("%w: %w" , ErrInvalidContainer , err )
249
+ }
250
+ reader , err := c .ObjectSearchInit (ctx , containerID , s , prm )
251
+ if err != nil {
252
+ return nil , fmt .Errorf ("failed to initiate object search: %w" , err )
253
+ }
254
+ defer reader .Close ()
255
+
256
+ err = reader .Iterate (func (oid oid.ID ) bool {
257
+ objectIDs = append (objectIDs , oid )
258
+ return false
259
+ })
260
+ if err != nil {
261
+ return nil , fmt .Errorf ("error during object IDs iteration: %w" , err )
262
+ }
263
+ return objectIDs , nil
264
+ }
265
+
266
+ // GetSDKClient returns a NeoFS SDK client configured with the specified address and context.
267
+ // If timeout is 0, the default timeout will be used.
268
+ func GetSDKClient (ctx context.Context , addr string , timeout time.Duration ) (* client.Client , error ) {
269
+ var prmDial client.PrmDial
270
+ if addr == "" {
271
+ return nil , errors .New ("address is empty" )
272
+ }
273
+ prmDial .SetServerURI (addr )
274
+ prmDial .SetContext (ctx )
275
+ if timeout != 0 {
276
+ prmDial .SetTimeout (timeout )
277
+ prmDial .SetStreamTimeout (timeout )
278
+ }
279
+ c , err := client .New (client.PrmInit {})
280
+ if err != nil {
281
+ return nil , fmt .Errorf ("can't create SDK client: %w" , err )
282
+ }
283
+
284
+ if err := c .Dial (prmDial ); err != nil {
285
+ if status .Code (err ) == codes .Unimplemented {
286
+ return c , nil
287
+ }
288
+ return nil , fmt .Errorf ("can't init SDK client: %w" , err )
289
+ }
290
+
291
+ return c , nil
292
+ }
0 commit comments