package container import ( "context" "errors" 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(ctx context.Context, idUser *user.ID) ([]cid.ID, error) { var cidList []cid.ID var err error cb := func(id cid.ID) error { cidList = append(cidList, id) return nil } if err = c.IterateContainersOf(ctx, idUser, cb); err != nil { return nil, err } return cidList, nil } // iterateContainers iterates over a list of container identifiers // belonging to the specified user of FrostFS system and executes // `cb` on each element. If idUser is nil, calls it on the list of all containers. func (c *Client) IterateContainersOf(ctx context.Context, idUser *user.ID, cb func(item cid.ID) error) error { var rawID []byte if idUser != nil { rawID = idUser.WalletBytes() } itemCb := func(item stackitem.Item) error { id, err := getCIDfromStackItem(item) if err != nil { return err } if err = cb(id); err != nil { return err } 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(itemCb, batchSize, cnrHash, containersOfMethod, rawID) if err != nil && errors.Is(err, unwrap.ErrNoSessionID) { return c.iterate(ctx, idUser, cb) } return err }