package container import ( "errors" "fmt" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) // ContainersOf returns a list of container identifiers belonging // to the specified user of FrostFS system. If idUser is nil, returns the list of all containers. // // If remote RPC does not support neo-go session API, fallback to List() method. func (c *Client) ContainersOf(idUser *user.ID) ([]cid.ID, error) { var rawID []byte if idUser != nil { rawID = idUser.WalletBytes() } var cidList []cid.ID cb := func(item stackitem.Item) error { rawID, err := client.BytesFromStackItem(item) if err != nil { return fmt.Errorf("could not get byte array from stack item (%s): %w", containersOfMethod, err) } var id cid.ID err = id.Decode(rawID) if err != nil { return fmt.Errorf("decode container ID: %w", err) } cidList = append(cidList, id) return nil } // We would like to have batch size as big as possible, // to reduce the number of round-trips and avoid creating sessions. // The limit depends on 2 things: // 1. VM limits: max 2048 items on stack. // 2. JSON encoded size for the item with type = 128k. // It turns out, that for container ID the second limit is hit first, // 512 is big enough value and it is beautiful. const batchSize = 512 cnrHash := c.client.ContractAddress() err := c.client.Morph().TestInvokeIterator(cb, batchSize, cnrHash, containersOfMethod, rawID) if err != nil { if errors.Is(err, unwrap.ErrNoSessionID) { return c.List(idUser) } return nil, err } return cidList, nil }