package searchsvc import ( "context" "crypto/ecdsa" "errors" "fmt" "io" "sync" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" rpcclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" ) type requestForwarder struct { OnceResign *sync.Once Request *objectV2.SearchRequest Key *ecdsa.PrivateKey } func (f *requestForwarder) forwardRequest(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) ([]oid.ID, error) { var err error // once compose and resign forwarding request f.OnceResign.Do(func() { // compose meta header of the local server metaHdr := new(session.RequestMetaHeader) metaHdr.SetTTL(f.Request.GetMetaHeader().GetTTL() - 1) // TODO: #1165 think how to set the other fields metaHdr.SetOrigin(f.Request.GetMetaHeader()) f.Request.SetMetaHeader(metaHdr) err = signature.SignServiceMessage(f.Key, f.Request) }) if err != nil { return nil, err } var searchStream *rpc.SearchResponseReader err = c.RawForAddress(addr, func(cli *rpcclient.Client) error { searchStream, err = rpc.SearchObjects(cli, f.Request, rpcclient.WithContext(ctx)) return err }) if err != nil { return nil, err } // code below is copy-pasted from c.SearchObjects implementation, // perhaps it is worth highlighting the utility function in frostfs-api-go var ( searchResult []oid.ID resp = new(objectV2.SearchResponse) ) for { // receive message from server stream err := searchStream.Read(resp) if err != nil { if errors.Is(err, io.EOF) { break } return nil, fmt.Errorf("reading the response failed: %w", err) } // verify response key if err = internal.VerifyResponseKeyV2(pubkey, resp); err != nil { return nil, err } // verify response structure if err := signature.VerifyServiceMessage(resp); err != nil { return nil, fmt.Errorf("could not verify %T: %w", resp, err) } chunk := resp.GetBody().GetIDList() var id oid.ID for i := range chunk { err = id.ReadFromV2(chunk[i]) if err != nil { return nil, fmt.Errorf("invalid object ID: %w", err) } searchResult = append(searchResult, id) } } return searchResult, nil }